Conceptio › Archive › arXiv CS
arXiv CS open access

Technical Report: A Formal Semantics for Java Symbolic Evaluation using Large-Block Encoding

2026 · arxiv_cs
arXiv CS · Papers · 2026
Open Source ↗Direct PDF ↓
software-architecturesoftware-engineeringtesting
Conceptio Open Archive

Analyze & explore related research in Conceptio

Connect this record directly into your research workflow or AI agent. Explore citations across open repositories, query full text, and export structured proof bundles.

Technical Report: A Formal Semantics for Java Symbolic Evaluation using Large-Block Encoding Soha Hussein1*, Stephen McCamant2 , Kelton OBrien3 , Kuen-Bang Hou (Favonia)2 , Michael Whalen4 , Vaibhav Sharma4

arXiv:2608.04513v1 [cs.SC] 5 Aug 2026

1*

Faculty of Computer and Information Sciences, Ain Shams University, Egypt. 2 Faculty of Computer Science and Engineering, University of Minnesota, USA. 3 Luddy School of Informatics, Computing, and Engineering, Indiana University, USA. 4 Amazon Web Services, USA.

*Corresponding author(s). E-mail(s): soha.hussein@cis.asu.edu.eg; Contributing authors: mccamant@cs.umn.edu; kelpobri@iu.edu; kbh@umn.edu; mww@amazon.com; svaib@amazon.com; Abstract Symbolic execution plays a critical role in software reliability, as they are used to find bugs, generate test cases, and provide correctness guarantees, particularly for safety-critical systems. Yet their own correctness is rarely subject to formal scrutiny, as it is typically established empirically by evaluating tool behavior across many programs. This leaves open the possibility that the tools themselves introduce unsoundness, potentially invalidating the verification results they produce and undermining the very guarantees they are meant to provide. In this paper, we address this gap by providing the formal treatment of symbolic execution with path-merging, an optimization that improves path explosion by summarizing branching code regions into disjunctive constraints rather than exploring each path independently. Specifically, we target Java Ranger, a pathmerging tool for Java programs that progressively transforms imperative Java code toward the language of formal logic through a series of code transformations. We formalize each of these transformations and prove their soundness with respect to a simplified version of the Java concrete semantics, establishing that Java Ranger’s path-merging process preserves program semantics.

1

Keywords: Symbolic Execution, Path-Merging, Program Analysis, Compilers, Program Proofs: Technical Report

1 Introduction Symbolic execution (SE) [1] is a formal testing and verification technique that ensures reliability and safety of programs, particularly for critical software where correctness guarantees are essential. Rather than executing programs on concrete inputs, SE treats inputs as symbolic values and explores program paths by collecting path conditions; i.e., logical constraints that characterize the inputs that reach each path. This generality makes SE applicable to a wide range of tasks including test input generation [2, 3], program and specification repair [4, 5], equivalence checking [6, 7], vulnerability finding [8, 9], invariant discovery [10], and protocol correctness checking [11]. Despite the widespread use of symbolic execution for assuring critical software, surprisingly little attention has been paid to formally establishing the correctness of the tools themselves. This creates a peculiar situation: we rely on symbolic execution to verify programs, yet the verifiers remain unverified. In practice, confidence in these tools is built empirically by running them on many programs and observing their behavior over time. While this approach can surface errors that manifest as visible failures (crashes or obviously incorrect results), it provides no formal guarantees about the tool’s correctness. The benchmarking practices in the field reflect this empirical approach. The Software Verification Competition (SV-COMP) [12] provides a large suite of programs with known verdicts against which tools are tested. Notably, the competition’s scoring scheme explicitly anticipates unsound behavior: a tool is penalized 16 points for incorrectly reporting a safe program as unsafe (false positive), and 32 points for incorrectly reporting an unsafe program as safe (false negative) [13]. The asymmetric penalties acknowledge that claiming safety incorrectly is more dangerous than spurious warnings, but the very existence of these penalties assumes that tools will produce wrong answers. This assumption is borne out in practice. In SV-COMP 2026, among 7 participating tools for Java verification, 4 tools produced a combined total of 21 incorrect verdicts: GDart (2), JBMC (14), jLiSA (1), and MLB (4). It is crucial to distinguish between two fundamentally different sources of incorrect verdicts. First, bounded search (depth limits, timeouts) may prevent complete exploration. A ”safe” verdict could be sound for all explored paths but incomplete for the full program. Second, tools may contain flaws in their core reasoning: bugs in modeling language semantics, program translation, or constraint solving. Here, even explored paths are analyzed incorrectly. Without formal semantics, these failure modes are indistinguishable, if at all observable. Users cannot tell whether ”safe” means the bug was unreached or incorrectly analyzed. Formal semantics and soundness proofs address the second problem (the focus of our paper): ensuring that whatever a tool analyzes, it analyzes correctly. Ironically, even establishing ground truth for verification benchmarks is challenging due to a circular dependency: benchmarks rely on tools to reveal bugs, yet we need 2

correct verdicts to evaluate whether tools work correctly. This is reflected in practice: verification tasks are often added to SV-COMP with provisional verdicts, which are later revised when tools discover previously undetected bugs. Even tools with strong empirical track records can harbor subtle soundness bugs that remain undetected for years. Java-Ranger won Gold Medals at SV-COMP in 2020, 2021, and 2025, yet during this work, we discovered a bug that had existed since its inception in 2020. The bug resided in field transformation: when a field operation followed a method invocation, the SSA construction failed to account for possible side effects on the field value, producing incorrect summaries. This bug was never caught by test suites or competition evaluations. It only surfaced when we attempted to prove soundness of the transformation and the proof failed. This exemplifies what formal verification of tools provides: bugs that are invisible to empirical testing become provably impossible when the tool’s correctness is established formally. In this paper, we address this gap by targeting the most semantically complex component of symbolic execution tools, where the risk of unsoundness is highest. Formally verifying a complete symbolic execution engine end-to-end is an ambitious undertaking that remains an open challenge, but a natural first step is to focus on the component whose incorrectness would have the most severe consequences. We therefore target Java Ranger (JR), a symbolic execution tool with path-merging for Java programs. JR operates by identifying regions of code where branching is about to occur during dynamic exploration, and attempts to collapse each such region into a disjunctive predicate that collectively describes the behavior of all paths through it. This summarization is achieved through a sequence of systematic transformations, each of which abstracts away one language feature, progressively moving the representation of the region from imperative Java toward the language of formal logic. A bug in any one of these transformations could silently corrupt the summary, causing JR to report verdicts that do not reflect the behavior of the original program. We therefore formalize each of JR’s transformations as operating on an intermediate representation (IR) and prove their soundness with respect to the concrete semantics of the IR. Through the proof, we establish that the produced summaries faithfully preserve program semantics. Although the formalization we provide in this paper is not machine-checked, we view this as a foundational step toward a broader formal treatment of symbolic execution tools. The remainder of the paper is organized as follows. Section 2 presents an overview of Java Ranger and its transformations. Section 3 presents related work and Section 4 presents the concrete semantics of the bytecode-like language that we use for proving soundness of JR transformations. Section 5 presents the underlying assumptions and structure of traditional symbolic execution and Section 6 presents the initial state of Java Ranger and its environment. The subsequent sections (Section 6.2Section 14) formalize and prove the soundness of each transformation in turn: γ -creation (Section 6.2), which identifies the region of interest for summarization; early-return elimination (Section 8 and Section 9), which normalizes control flow by removing intermediate returns; variable renaming (Section 10), which ensures variable names are unique across paths; variable substitution (Section 11), which propagates variable definitions forward through the region; method inlining (Section 12), which

3

eliminates method invocations by substituting their definitions; and field SSA creation (Section 13), which converts field operations into SSA form while accounting for possible side effects of method invocations. Finally, Section 15 brings the transformations together, presents the Java Ranger fixpoint algorithm, and proves the soundness of the overall path-merging process.

2 Java Ranger Overview Java Ranger is a path-merging symbolic execution for Java programs that operates by identifying regions of code where branching is about to occur during dynamic exploration, and attempts to collapse each such region into a disjunctive predicate that collectively describes the behavior of all paths through it. This summarization is achieved through a sequence of systematic transformations, each of which abstracts away one language feature, progressively moving the representation of the region from imperative Java toward the language of formal logic. The transformation pipeline proceeds as follows. The higher-order transformation eliminates method invocations by inlining their definitions into the region. The field transformation eliminates heap references by introducing Static Single Assignment (SSA) local variables that reflect the value or computation associated with each reference. Finally, single-path-cases identifies constructs that resist summarization, such as heap allocations and exceptions, and marks them as exit points to be explored individually. Together, these transformations produce a disjunctive constraint that Java Ranger submits to the underlying constraint solver in place of enumerating each path individually. At any point during the summarization, if any of the transformations fails, then JR reverts to using traditional SE exploring each path separately. For example, consider the code in Listing 1. The code takes in an integer and it separates the number of set bits from the remaining bits. For example, for i = 20 the output is 11000000, assuming that i is an 8-bit integer. To do that, the program runs in a loop while i is not equal zero. In each iteration, it checks if the rightmost bit is one line 4. If yes, then the program performs an unsigned right shift, sets the leftmost bit on (line 10), and removes the rightmost bit in i (line 11). Otherwise, the program tries to find the number of rightmost trailing zeros, and then shifts i by that number (lines 7, 9). 1public int separateBits ( int i ) { 2 int j = 9; 3 while ( i != 0) { 4 int hasZeroTrail = ( i & 1); 5 if ( hasZeroTrail == 0) { 6 int numOfZeros = Integer . numTrailZero ( i ); 7 i = i >> numOfZeros ; 8 } else { 9 j = j >>> 1; 10 j = j * Integer . reverse (1); 11 i = i >> 1; 12 } } 13 return j ; } Listing 1: Example: separates the number of set bits from the remaining bits

4

To analyze the program with symbolic execution, at each iteration of the while loop operating over a single bit, there are two possibilities that the program needs to analyze. This results in a number of paths that are exponential in the number of bits in i, i.e., 232 paths for an unrestricted 32-bit i. Using JR one can explore the same program by collapsing branches inside the while loop (lines 5-12), as well as those that exist in numTrailZero, resulting in exploring a maximum of 16 paths for the same input. JR operates in two phases, a static phase, and a dynamic phase. The static phase analyzes the code to be executed and identifies potential regions of code that could be merged. The dynamic phase attempts to summarize a specific code region into a disjunctive constraint. It does so by translating the Java features through a sequence of transformations. We now talk in detail about these two phases.

2.1 Static Phase During the static phase, the region’s to-be-merged code is first recovered into a statement in JR’s intermediate representation (IR), and processed through a series of static transformations, i.e., transformations that are not dependent on the dynamic values/objects. In general, Java Ranger starts by creating the Control Flow Graph (CFG) of the program’s bytecode. It then scans the graph to find basic blocks with conditional instructions, i.e., a basic block with two successors. If one is found, it translates the basic blocks between the conditional instruction and its immediate post dominator as an if-statement in JR’s IR. JR avoids recovering statements with loops. This is done by disregarding a subgraph whose post-dominator that is also a predecessor of a node. While JR will disregard recovering this subgraph, it will attempt to recover other subgraphs within the identified loop. In other words, JR does not attempt to summarize loops but can summarize statements within a loop if no inner loop exists. For example, the recovered JR IR-statement for the example in Listing 1 is: 1 if ( w7 != 0) { 2 w11 := w19 >>> 1; 3 w13 := invoke ( w13 , Integer , reverse ( I )I ,1) 4 w14 := w11 ˆ w13 ; 5 w15 := w18 >> 1; 6 } else { 7 invoke ( w9 , Integer , numTrailZero ( I )I , w18 ) 8 w10 := w18 >> 1; }; 9 ϕ( w16 , w15 , w10 ); 10 ϕ( w17 , w14 , w19 ); Listing 2: Initial IR statement for seperateBits

Where w7 refers to hasZeroT rail variable, the first definition of i is w18, and finally the first definition of j is w19. After the control flow graph is translated into JR’s IR, JR applies three static transformations: ϕ-expressions elimination, early-returns elimination and finally alpha renaming of variables.

5

1. γ-Creation: In this transformation all if-statements with ϕ-expressions, are rewritten to assignment statements, where the expression of assignments are γ -expressions capturing the semantics of the ϕ-statements. For example, the if-statement in Listing 2 at line 1 has two trailing ϕ-statements (ϕ(w16, w15, w10) and ϕ(w17, w14, w19)) capturing the changes to the i variable in Listing 1 in lines 7,11, and the changes to the j variable also in the same figure at 9, 10, respectively. In the γ -creation transformation, these ϕ-statements are replaced with assignment statements with γ -expressions. For example, lines 10,11 in Listing 3 shows the corresponding assignment statements created for these ϕstatements. 1 if ( w7 != 0) { 2 w11 := w19 >>> 1; 3 invoke ( w13 , Integer , reverse (I )I , 1) 4 w14 := w11 ˆ w13 ; 5 w15 := w18 >> 1; 6 } else { 7 invoke ( w9 , Integer , numTrailZero (I )I , w18 ) 8 w10 := w18 >> 1; } 9 w16 := γ ( w7 !=0 , w15 , w10 ); 10 w17 := γ ( w7 !=0 , w14 , w19 ); Listing 3: IR after γ-creation transformation

2. Early-Returns Elimination: For code regions where multiple return statements exists, in this transformation, we construct two expressions, a conditional-returnexpression, and a return path constraint. The conditional-return-expression describes, for each variable, the inner relative path constraint for assigning variables. On the other hand, the return path constraint describes all relative conditions that can exist within a region. the a var. A one that describes explicit return statements, all return statements are collapsed into a single assignment of a symbolic return-variable, with the appropriate return condition captured in a γ -expression. For example, while there are no early-returns in seperateBits there are early returns in the invoked method numT railZero(I )I . Listing 4 shows JR IR-statement recovered from the definition of this method. Applying early-return elimination transformation results in listing 5 where erResult is a symbolic return variable. 1 if ( w1 == 0) { 2 return w4 3 } else { 4 skip ; 5 } 6 ... 7 w27 := w24 << 1; 8 w28 := w27 >>> 31; 9 w29 := w25 - w28 ; 10 return w29

1 2 3 4 5 6 7 8 9 10

Listing 4: IR for numT railZero

if ( w1 == 0) { skip ; } else { skip ; } ... w27 := w24 << 1; w28 := w27 >>> 31; w29 := w25 - w28 ; skip ; erResult := γ (( w1 == 0) , w4 , w29 ); Listing 5: IR after early-return

6

3. α-Renaming: In this transformation all local variables of Java Ranger are appended a unique index. More precisely, every variable is now a pair of a variable and a unique index. This index is useful to identify multiple encounters of the same region of code during different parts of the execution. Here, since this the first encounter all variables with be paired with a unique index 1. In this example all local variables are appended with the number 1, both in the IR statement as well as inside the Ranger state. 1 if (( w7 ,1) != 0) { 2 ( w11 ,1) := ( w19 ,1) >>> 1; 3 invoke (( w13 ,1) , Integer , reverse (I )I ,1) 4 ( w14 ,1) := ( w11 ,1) ˆ ( w13 ,1); 5 ( w15 ,1) := ( w18 ,1) >> 1; 6 } else { 7 invoke (( w9 ,1) , Integer , numTrailZero ( I)I , ( w18 ,1)) 8 ( w10 ,1) := ( w18 ,1) >> 1; } 9 ( w16 ,1) := γ (( w7 ,1) !=0 , ( w15 ,1) , ( w10 ,1)); 10 ( w17 ,1) := γ (( w7 ,1) !=0 , ( w14 ,1) , ( w19 ,1)); Listing 6: IR for seperateBits after α-renaming

2.2 Dynamic Phase In this phase, JR uses the state of the dynamic environment in an attempt to eliminate additional Java language features, such as method invocation, field operations and exceptions. The idea here is that using the dynamic state JR can reduce the possibilities of dispatched methods, fields and specific exceptions. This phase consists of four main transformations 1. Local Variable Substitution: The substitution transformation substitutes values of the region’s inputs that are defined in I . In this example, I is defined to contain w7, w18 and w19 with instantiation-time values being the symbolic expressions ia & 1, ia , and 0 respectively. 1 if ( i_a & 1 != 0 ) { 2 ( w11 ,1) := 0 >>> 1; 3 invoke (( w13 ,1) , Integer , reverse (I )I ,1) 4 ( w14 ,1) := ( w11 ,1) ˆ ( w13 ,1); 5 ( w15 ,1) := i_a >> 1; 6 } else { 7 invoke (( w9 ,1) , Integer , numTrailZero ( I)I , i_a ) 8 ( w10 ,1) := i_a >> 1; } 9 ( w16 ,1) := γ (( i_a & 1) !=0 , ( w15 ,1) , ( w10 ,1)); 10 ( w17 ,1) := γ (( i_a & 1) !=0 , ( w14 ,1) , 0); Listing 7: IR for seperateBits after substitution

2. Method Inlining: To enable method inlining two main steps need to occur. The first binds the passed parameters to the invoked method arguments, the second captures the return value if one exists as an assignment in the caller. This transformation also inlines recursive functions up to a preconfigured depth. For example

7

listing 8 shows inlining, where (w9, 1) holds the return expression from invoking numTrailZero. 1 if (( i_a & 1) != 0 ) { 2 ( w11 ,1) := 0 >>> 1 ; 3 ... 4 } else { 5 if (!( i_a != 0)) { 6 skip ; 7 } else { 8 skip ; } 9 ... 10 ( w9 ,1) := γ (!( i_a !=0) , 32 , else ( w29 ,3)); 11 ( w10 ,1) := i_a >> 1; } 12 ( w16 ,1) := γ ( i_a &1!=0 , ( w15 ,1) , ( w10 ,1)); 13 ( w17 ,1) := γ ( i_a &1!=0 , ( w14 ,1) , 0); Listing 8: IR for numT railZero after method-inlining

3. Field and Arrays GSA Creation: The intuition behind this transformation is that, all fields updates can replaced with some fresh ssa local variable that are uniquely indexed. Likewise all fields look-ups are replaced with the corresponding ssa variable. Creating these local variables and using them sensibly to reflect field updates and lookups, is the purpose of this transformation. Therefore the output of this transformation is a bunch of local variable assignments, with no field lookup or update statements. 4. Single Path Cases: Java Ranger avoids summarizing object creation and exceptions due to some architectural limitations. However, giving up on path-merging of all code regions that are enclosing object creations or exceptions, would mean that Java Ranger will give up on potentially many useful merges. Thus, we have introduced the Single Path Cases transformation. In this transformation, Java Ranger identifies two constraints, the first capturing the relative conditions of statements it can summarize, while the second capturing the relative conditions of statements that it cannot summarize, and where traditional symbolic execution needs to dynamically execute. In our motivational example, JR was able to summarize all the code region. However introducing a print statements on the else side would result in two predicates, one that describe the summary of the code region without the branch that contains the print statement, and another that is used to target the execution of SSE to it. 5. Linearization: In this transformation, if-statements are removed, and statements on the then and the else side are composed in a sequential composition. This is possible now at this transformation because all local variable assignments are guarded, i.e., are captured by the condition in γ -statements.

8

1 2 3 4 5 6 7 8 9 10 11

( w15 ,1) := i_a >> 1 ; ( w7 ,3) := i_a << 16 ; ( w9 ,3) := γ (( w7 ,3)!=0 , ( w7 ,3) , i_a ); ( w10 ,3) := γ (( w7 ,3)!=0 , 15 , 31); ( w12 ,3) := ( w9 ,3) << 8; ( w13 ,3) := ( w10 ,3) - 8; . . . ( w9 ,1) := γ ( ( i_a ==0) , 32 , ( w29 ,3)); ( w10 ,1) := i_a >> 1; ( w16 ,1) := γ ( i_a &1!=0 , ( w15 ,1) , ( w10 ,1)); ( w17 ,1) := γ ( i_a &1!=0 , -2147483648 , 0); Listing 9: IR’s snippet for numT railZero after linearization

After all the transformations are executed successfully, Java Ranger proceeds as follows. First, JR will create a conjunctive constraint of all the expressions that resulted from the linearization transformation. Then, it will create an execution path to explore the unsummarized behavior from the single path cases, as well as, another one to explore returns from the early return transformation. Finally, Java Ranger will set up the state of variables in each case, and will allow SE to resume execution by exploring these paths. Next, we will show the formal semantics of JR’s transformations, and the soundness proofs of the main transformations. The general form of the proof of the soundness of JR is to establish correspondence between any of JR transformations and the execution of the concrete semantics. For if JR is sound with respect to concrete semantics, then using JR in a symbolic execution would be sound as long as the symbolic execution is sound and correct. Thus in the rest of the paper is organized as follows: first we present the concrete semantics which we will use to show the soundness of JR’s transformations, next, we will present the semantics of main JR’s transformations along with their soundeness proofs, and finally, present the overall algorithm of JR.

3 Related Work Path explosion is one of the most commonly observed scalability challenges of symbolic execution, and works prior to Java Ranger have explored a variety of path merging approaches. In symbolic execution tools that represent multiple complete symbolic execution states, one natural approach is to implement a merging operation on these state representations. Hansen et al. [14] and Kuznetsov et al. [15] explored such statemerging techniques, and MultiSE [16] achieves a similar effect within a somewhat different tool architecture. By contrast, Java Ranger takes a different approach of statically summarizing code regions with branching control-flow, more closely related to the Veritesting approach of Avgerinos et al. [17] in their system MergePoint for binary executables. The static summarization approach is easier to adopt in a symbolic execution tool that is designed to have only on execution state at once, like Symbolic PathFinder (SPF) [18] that Java Ranger builds upon. Java Ranger is significantly different from MergePoint because of the differences between binary code and Java bytecode: for instance Java Ranger

9

can take advantage of structured control-flow, but needs to perform its own method inlining because of the prevalence of small methods in Java. Many of the invariants (such as SSA form) and transformations (such as method inlining and constant propagation) used by Java Ranger are similar to techniques used in compilers, and compilers are the language transformation tools for which correctness proof techniques are most developed. The two main classes of verification tools for compilers are translation validators [19–21], which check the correctness of a particular compilation run, and certified compilers, such a CompCert [22] for C and CakeML [23] for Standard ML, which are proven once-and-for-all to compile any input program correctly. Our proofs about Java Ranger are once-and-for-all, but in being transformations within an intermediate representation, they are similar to correctness verification of individual compiler passes [24–27]. A number of previous formal descriptions of symbolic execution have been language-agnostic or used simple languages for clarity. Schwartz et al. [28] use a simple formal language to explain taint analysis and symbolic execution, though they also mention a number of practical implementation concerns. De Boer and Bonsangue [29] use a transition system model to formalize symbolic execution for a sequence of languages of increasing complexity. In a recent work, Voogd et al. [30] present a denotational semantics for symbolic execution along with a machine-checked formalization. The formalization of Porncharoenwase et al. [31] has the closest purpose to ours in introducing an abstract form of state merging, which generalizes path merging and can be applied to code with loops and recursion. They described a machine-checked implementation for a core subset of Scheme and more realistic optimized tool that is tested against it.

4 Semantics of Concrete Execution In this section, we define the concrete execution semantics that will be used to establish the soundness of JR’s transformations. The intermediate representation employed by JR is based on a variation of the Java bytecode without the operand stack, expressed in single static assignment (SSA) form [32], where each variable is assigned exactly once.

4.1 Concrete Grammar Figure 1 presents the grammar of JR’s IR. The metavariables used throughout the semantics range over the following domains. Integers n ∈ Z and positive subscripts j ∈ Z+ ⊎{⊥} are used to index and distinguish program variables, where ⊥ denotes the absence of a subscript. Variable identifiers a ∈ Id name program variables, field names f ∈ F denote object fields, class names c ∈ C range over the set of declared classes, method signatures g ∈ G identify methods, and references r ∈ R denote concrete heap addresses. Note that references are always concrete and are never permitted to take symbolic values. The expression language of the grammar includes standard literals, variables, and both unary and binary expressions. In addition, it features the γ -expression, which

10

integer n ∈ Z class c ∈ C

subscript j ∈ Z+ ⊎ {⊥} signature g ∈ G

identif ier a ∈ Id ref erence r ∈ R

f ield f ∈ F

v ::= n | true | f alse | null var x, y, i, o, t ::= (a, j ) − m ::= (→ x .s) unaryOp ::= − |! ⋄ ::= + | − | ∗ | ÷ | & | bitwise − or | ⊕ | % |==|! =|≤|≥ | && | logical-or |> |< |≪|≫ exp e ::= v | x | e1 ⋄ e2 | e | γ (e, e1 , e2 ) simple-ref. z ::= r | x stmt s ::= s1 ; s2 | x := e | skip | if e then s1 else s2 ; ϕ-stmt − | invoke(x, z, g, → y ) | return e | put f ield(z, f, e) | get f ield(x, z, f ) | new(x, c) ϕ-stmt phis ::= ϵ | ϕ(x, e1 , e2 ); ϕ-stmt literal method binaryOp

Figure 1: Context Free Grammar for Concrete Execution

serves as a compact representation of the conventional conditional (if-then-else) expression. We use x, y, i, o, t to range over variables. Each variable is represented as a pair consisting of a name and a unique index, i.e., (a, j ), where the index distinguishes different instances of the same variable across multiple executions of a code region. Furthermore, the IR models references through simple references z , which may either be concrete references r or reference variables x. Fields are denoted by f , classes by c, and method signatures by g . The statement language includes assignments, sequential composition (treated as an associative operator), the skip statement, and conditional statements of the form if, augmented with trailing ϕ-functions to capture the merging of variable values − across branches. Method invocation is represented as invoke(x, z, g, → y ), where x re− ceives the result of invoking method g on reference z with arguments → y . The IR also includes return statements return e, field update statements put f ield(z, f, e), which assign the value of expression e to field f of reference z , and field access statements get f ield(x, z, f ), which read the value of field f from reference z into variable x. Finally, object creation is represented by new(x, c), where a new object of class c is allocated and assigned to reference variable x. Note that the full implementation of JR also supports array load and store operations. However, since these can be modeled as specific instances of field operations, we omit their formal treatment here without loss of generality.

11

vals: V = Z ⊎ {true, f alse, null} ⊎ R

δ = (Θ, η, ∆, Hν, mu) → stmt) method-stmt: Θ : C × G −→ method(− var, ref-type: η:R −→ C locals: ∆ : (Id, Z+ ⊎ {⊥}) −→ V heap: H :R×F −→ V new-fresh: ν∈N return-value: µ ∈ V ⊎ {⊥} Figure 2: Environments and functions of Concrete Semantics

4.2 Concrete Environment Fig. 2 presents the components of the concrete semantic environment δ = (Θ, η, ∆, H, ν, µ). The environment captures the essential runtime state required for execution. In particular, Θ maps method statements to their corresponding signatures, while η maps reference identifiers to their associated types. The mapping ∆ represents the local variable environment, and H denotes the heap, which maps objects-fields pairs (R × F ) to their associated values. The component ν is a counter used to generate fresh object identifiers during allocation, and µ records return values produced during execution. Values in the semantic domain are drawn from the set Z of integers, the Boolean constants {true, false}, the distinguished value null, and the set of concrete references R.

4.3 Concrete Semantic Rules We present the evaluation rules of the concrete semantics in Appendix B1. The rules are standard operational semantics rules capturing the execution of statements in JR’s IR. In particular, the composition rule enforces sequential execution of statements s1 and s2 . The corresponding composition-ret rule handles the case in which s1 evaluates to a return statement, in which case execution of s2 is ignored. The invoke rule define the semantics of method invocation. In this rule, the reference expression z is first evaluated to a concrete reference r, which is then used together with the method signature g to retrieve the corresponding method body from Θ. A fresh environment is constructed by binding the formal parameters of the method to → − → − the evaluated argument values ({( y ′ , v ′ )}), after which the method body is executed. Upon completion of the method body, the local environment ∆ is restored, and the return value is recorded in µ and assigned to the target variable x (∆[x ← µ′ ]). Conditional execution is captured by the if-true, if-false, if-true-ret, and if-false-ret rules. In the non-returning cases (if-true and if-false), the condition expression e is evaluated to determine the branch to execute, followed by execution of the selected branch and the corresponding ϕ-statements. In the presence of a return

12

statement within the s1 branch (if-true-ret and if-false-ret), execution of the ϕ-statements is skipped, and the return value is propagated via µ′ . The getfield and putfield statements follow the standard semantics of heap access. In both cases, the reference expression z is evaluated to a concrete reference r, after which the corresponding field f is either read from or updated in the heap H . Finally, object creation is handled by the new rule, which guarantees the generation of fresh references. Each new object is assigned a unique reference r produced by the freshRef function, which consumes the current counter value ν to ensure global freshness.

4.4 Evaluation Rules All evaluation judgments can be extended to work for vector of expressions, that is → − − ⊢ (ω, → e ) 7→t (ω ′ , e′ ) is defined as

→ − e = e1 . . . en

⊢ (ω, e1 ) 7→t (ω ′ , e′1 ) · · · ⊢ (ω, en ) 7→t (ω ′ , e′n ) → − − ⊢ (ω, → e ) 7→ (ω ′ , e′ )

→ −′ e = e′1 . . . e′n

vec

t

Figure 4: Applying evaluation/rewriting over a vector of expressions

4.5 Concrete Evaluation Properties We assume the following properties hold over the concrete semantics

• Statement must be defined in an SSA form (Property A.1). • Statement s always has at most a single return within an if-statement (Property A.2). • Each class has an class object reference which can be used to make static invocation (Property A.4). • All formal arguments of every method body in Θ are used in its statement (Property A.5). Next, we show the following lemma which are easy consequence of the rules of the concrete semantics and the SSA property (full details in [33]).

Lemma 4.1. If for any reference r and classes c1 , c2 , such that Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) (r, c1 ) ∈ η ∧ (r, c2 ) ∈ η ′

then c1 = c2 . Proof The only statement that changes η is the new-statement, so after a reference-class pair are constructed η, it cannot be updated nor removed. On the other hand, adding a new pair

13

to η is always guaranteed to have a unique reference, since its creation is parametric by ν, which gets incremented with each invocation of a new-statement. □

Lemma 4.2. SSA(s) Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) then ∆ ⊆ ∆′ η ⊆ η′ Proof First observe that because s satisfies the generalized SSA property, it must be the case that variables are never remove nor updated, they can only be added. In particular for z, its mapping in both ∆ and ∆′ must be the same, more generally we must have that ∆ ⊆ ∆′ . Following a similar argument, we can conclude that references in η never remove nor updated, they can only be added. In particular for r, its mapping in both η and η ′ must be the same, more generally we must have that η ⊆ η ′ □

Lemma 4.3. If for any simple reference z and classes c1 , c2 such that SSA(s) Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) ∆ ⊢ z ⇝c r1 ∆′ ⊢ z ⇝c r2 (r1 , c1 ) ∈ η ∧ (r2 , c2 ) ∈ η ′

then c1 = c2 Proof First observe that because s satisfies the generalized SSA property, it must be the case that variables are never remove nor updated, they can only be added. In particular for z, its concrete evaluation in both ∆ and ∆′ must be the same, i.e., r1 = r2 , more generally we must have that ∆ ⊆ ∆′ . The only statement that changes η is the new-statement, so after a reference-class pair are constructed η, it cannot be updated nor removed. On the other hand, adding a new pair to η is always guaranteed to have a unique reference, since its creation is parametric by ν, which gets incremented with each invocation of a new-statement. □

5 Dynamic Symbolic Execution’s Environment In this section, we present the formal foundation of Dynamic Symbolic Execution (DSE) upon which Java Ranger’s path-merging capabilities are built. We assume a sound symbolic execution that operates over a concrete state (Θ, η, ∆, H, ν, µ) and a symbolic state (Θ, ηs , ∆s , Hs , π, µs ). The grammar of DSE follows the same structure as the concrete semantics in Fig. 1, with two key differences summarized in the unshaded variables in Fig. 5. 14

First, the value domain is extended from concrete values V to symbolic values Vs , allowing expressions to be used as values. Second, the environment is lifted accordingly. The method table Θs and reference typing ηs are carried over unchanged from their concrete counterparts Θ and η respectively; they appear with symbolic subscripts solely to distinguish the symbolic environment from the concrete one. The local state ∆s maps uniquely indexed variables (Id, n) to values in Vs , and the heap Hs maps reference-field pairs to values in Vs , where references remain concrete while field values may be symbolic. Method return values µs range over Vs ⊎ {⊥}, where ⊥ denotes the absence of a return value. Finally, the path condition π captures the symbolic constraint accumulated along the current execution path. We make the following assumptions on the symbolic environment (ηs , ∆s , Hs , π, µs ):

• reference typing mapping is carried over unchanged from the concrete semantics, ηs = η (Property A.7). • No symbolic references (Property A.21). • The Heap and local variable mapping of the concrete state is consistent with the symbolic state (Properties A.10 and A.9). • All variables in original statement, that is going to be rewritten, are not indexed (Property A.19). • Initial local variable mapping ∆s cannot have any use for any input variable i ∈ I in the Range(∆s ) (Property A.11).

6 Java Ranger’s Environment Java Ranger extends the environment of the DSE with the following environment variables: Path conditions are captured by the tuple Π = (π, πr , πs ), representing the current path condition, the return path condition, and a single-path condition, respectively. Region-specific variables are grouped in χ = (I, O, T ), denoting input, output, and temporary variables. Finally, the environment includes auxiliary components that are initialized once: a global counter u ∈ N used for generating unique identifiers, and a field subscript mapping P , which associates reference-field pairs with symbolic terms to track field accesses. In addition to the DSE assumption, Java Ranger makes the following assumptions about the symbolic state before it starts the summarization:

6.1 Java Ranger Initial State Lemma 6.1. If SSA(s) Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) ((Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), χ, u), s) −→t ((Θt , ηs , ∆′s , Hs′ , µ′s , (π ′ , πr′ , πs′ ), χ′ , u′ ), s′ ) ∆ |= (∆s , π ) then ∆′ |= (∆s , π ) 15

Algorithm 1: Algorithm for initialize-state where getInput(s) := {x | isU se(x, s) ∧ ¬isDef (x, s)} and getOutput(s) := {x | isDef (x, s)} 1

Input: Concrete State δ = (Θ, η, ∆, H, ν, µ) Input: Symbolic State (ηs , ∆s , Hs , π ) Assumption Prop A.6: µ = µs = ⊥ Assumption Prop A.7:ηs ⊆ η Assumption Prop A.9: ∆ |= (∆s , π ) Assumption Prop A.10: (∆, H ) |=H (∆s , Hs , π ) Assumption Prop A.11: ∀i ∈ getInputs(s).∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) Output: Path-Merging State ω Data: χ = (I, O, T ) Data: Π = (π, πr , πs ) − − Θt := {((πr′ , µ′s ), → y .s′ ) s.t. (→ y .s) ∈ Θ ∧ ((πr′ , µ′s ), s′ ) = transf orm(s)} πr := f alse πs := f alse I := getInput(s) O := getOutput(s) T := ∅ u := 0 return ω = (Θt , ηs , ∆s , Hs , µs , Π, χ, u)

6.2 Transformation Common Details Almost each transformation, except for the remove final-returns, has two statement judgments, one that is recursive, and another is a wrapper that initiate the transformation process. Thus, in the proof we follow the same order, for statements, we first show the the soundness of the recursive judgment then discuss the soundness of the wrapper. In the remainder of this paper, we present the formal semantics and soundness proofs of main JR’s transformations. More precisely, we present eight transformations: γ transformation (T R1 ), early-returns elimination (T R2 ), final-return elimination (T R3 ), renaming transformation (T R4 ), substitution transformation (T R5 ), method inlining transformation (T R6 ), field SSA transformation (T R7 ) and finally, constant reference propagation (T R8 ).

16

7 T R1 : γ-Creation Transformation

integer n ∈ Z subscript j ∈ Z+ ⊎ {⊥} identif ier a, b, c ∈ Id class c ∈ C signature g ∈ G f ield f ∈ F ref erence r ∈ R

literal v ::= n | true | f alse | null var x, y, i, o, t ::= (a, j ) → − method m ::= ( x .s) unaryOp ::= − |! binaryOp ⋄ ::= + | − | ∗ | ÷ | & | bitwise − or | ⊕ | % |==|! =|≤|≥| && | logical-or |> |< |≪|≫ exp e ::= v | x | e1 ⋄ e2 | e | γ (e, e1 , e2 ) simple-ref. z ::= r | x − stmt s ::= s1 ; s2 | x := e | skip | if e then s1 else s2 ; ϕ-stmt | invoke(x, z, γ, → y ) | return e put f ield(z, f, e) | get f ield(x, z, f ) | new(x, c) ϕ-stmt phis ::= ϵ | ϕ(x, e1 , e2 ); ϕ-stmt

Figure 6: γ -creation to-grammar

The γ -creation transformation is the first transformation applied by JR, rewriting trailing ϕ-statements at the end of if-statements as assignments over γ -expressions, thereby eliminating ϕ-statements from the program representation (Property A.12). The resulting grammar is shown in Fig. 6.

′

⊤ ⊢ s −→γ s′ s −→γ−wrap s′

γ −wrap

φ ⊢ s1 −→γ s1

′

φ ⊢ s2 −→γ s2

φ ⊢ s1 ; s2 −→γ s′1 ; s′2 ′

φ ∧ e ⊢ s1 −→γ s1

γ −comp φ ⊢ x := e −→γ x := e

γ −assign

′

φ ∧ ¬e ⊢ s2 −→γ s2

′ ′ φ ⊢ if e then s1 else s2 ; ϕ(x1 , e1 , e1 ); . . . ; ϕ(xk , ek , ek ) ′ ′ ′ ′ −→γ if e then s1 else s2 ; x1 := γ(φ ∧ e, e1 , e1 ); . . . ; xk := γ(φ ∧ e, ek , ek )

γ −if

noOpγ (s) φ ⊢ s −→γ s

γ −noOp

Figure 7: Gamma Creation Rules

Fig. 7 shows the rewrite rules for the γ -transformation. The rules define two judgments. The judgment φ ⊢ s −→γ s′ rewrites an IR statement s into s′ , where φ is a boolean flag encoding the local path condition within the statement, used to guide the rewriting of ϕ-expressions into γ -expressions. The wrapper judgment s −→γ-wrap s′ is the triggering judgment that initiates the rewriting, invoking the γ -judgment on s 17

with an initial true path condition. Also, the noOpγ (s) is defined as all statements except for if and sequential composition statements. noOpγ (x := e) = true − noOpγ (invoke(x, z, γ, → y )) = true noOpγ (get f ield(x, z, f )) = true noOpγ (put f ield(z, f, e)) = true noOpγ (return e) = true noOpγ (skip) = true noOpγ (s) = f alse otherwise

Lemma 7.1. Let s be any statement. If φ ⊢ s −→γ s′ ∆ ⊢ φ ⇝c true Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) then Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) Proof We will proof the lemma using structural induction on s. First, consider the γ-assign rule and all other statements where gamma transformation does not introduce any changes to the statement s. In all of these cases, the theorem statement holds trivially as there is no rewriting, i.e., changes introduced on the statement. Next, let us consider γ-if rule. Applying the rewriting we get φ ⊢ if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ); . . . ; ϕ(xk , ek , e′k ) −→γ if e then s′1 else s′2 ; x1 := γ(φ ∧ e, e1 , e′1 ); . . . ; xk := γ(φ ∧ e, ek , e′k ) such that φ ∧ e ⊢ s1 −→γ s′1 , and φ ∧ ¬e ⊢ s2 −→γ s′2 . There are four cases in which this statement can execute concretely, depending on whether the condition e evaluates to true or false, and whether s1 or s2 contains a return statement. Let us first consider the case where e evaluates to true (Θ ⊢ (∆, e) ⇝c true) and where the execution of s1 does not encounter a return statement. In this case, the result of evaluating s will be (ηs′ , ∆′ [x1 ← v1 , . . . , xk ← vk ], H ′ , ⊥) (applying the concrete rule if-phi-true), where ∆ ⊢ e1 ⇝c v1 . . . ∆ ⊢ ek ⇝c vk , and Θ ⊢ ((ηs , ∆, H, ν, µ), s1 ) ⇒c (ηs′ , ∆′ , H ′ , ν ′ , ⊥). Now, now to execute the rewritten statement, we know that the expression e must evaluate to the same true value, since it has not changed and it is executing in the same environment. This means that the execution will proceed by executing s′1 . But, here we can apply the induction hypothesis on s1 , which then implies that Θ ⊢ ((ηs , ∆, H, ν, µ), s′1 ) ⇒c (ηs′ , ∆′ , H ′ , ν ′ , ⊥). Similarly we know that Then evaluating the rewritten statement we get Θ ⊢ ((ηs , ∆, H, ν, ⊥), if e then s′1 else s′2 ⇒c (ηs′ , ∆′ , H ′ , ⊥) using if-true rule. Next, the remaining part of the rewritten expression will be evaluated by applying both the composition rule, and the assignment rule. Observe here that that all expression e and e1 , ..ek must evaluate to the same values concretely since the grammar uses an SSA formate and that means variables within expression cannot be redefined. More precisely, if an expression has evaluated to a particular value at one place in the code, then evaluating the same expression at a later point in the code will produce the same value. But evaluating the expression earlier in

18

the code might not be a valid thing to try. Moreover, recall that from the hypothesis we have that ∆ ⊢ φ ⇝c true. We also know that the ∆ ⊢ φ ∧ e ⇝c true, implying that all γ expressions will be evaluated to the true side, i.e., by applying the γ-true expression rule. This implies that the sequence of assignments will have the same effect on the environment as the if-phi-true rule, i.e., Θ ⊢ ((ηs′ , ∆′ [x1 ← v1 , . . . , xk−1 ← vk−1 ], H ′ , ⊥), xk := γ(e, ek , e′k ) ⇒c (ηs′ , ∆′ [x1 ← v1 , . . . , xk−1 ← vk−1 , xk ← vk ], H ′ , ⊥). Similarly, the proof for the case when the condition within the if-statement evaluates to false, and no return-statement is encountered during the execution of s2 , will follow the same reasoning, however, on s2 instead of s1 . The other two remaining cases for the execution of the if-statement are when the condition of the if-statement evaluates to either true, or false, but a return-statement is encountered during the evaluation of either s1 or s2 . These two cases are handled by the concrete rules if-phi-true-ret, and if-phi-false-ret. In what follows we show the proof for if-phi-true-ret, but if-phi-false-ret follows the same argument. In the if-phi-true-ret case, the evaluation will be different. The main difference is that, if a return occurs during the execution of the ”then” side, then the ϕs and the gamma assignments will both be skipped. Thus, in this case, the resulting state will be (ηs′ , ∆′ , H ′ , ν ′ , µ′ ), when evaluating the if-statement concretely, where µ′ ̸= ⊥, Θ ⊢ (∆, e) ⇝c true. This means that s′1 will be evaluated. However, we can apply induction on s′1 to obtain (ηs′ , ∆′ , H ′ , ν ′ , µ′ ). Θ ⊢ ((ηs , ∆, H, ν, µ), s1 ) ⇒c (ηs′ , ∆′ , H ′ , ν ′ , µ′ ). But since we have assumed that µ′ ̸= ⊥, then the rewritten if-statement then will evaluate to (ηs′ , ∆′ , H ′ , ν ′ , µ′ ). Next, consider γ-comp rule. Here we want to In this case, the statement is rewritten as: φ ⊢ s1 ; s2 −→γ s′1 ; s′2 , where φ ⊢ s1 −→γ s′1 , and φ ⊢ s2 −→γ ⇒c s′2 . Evaluating the original statement we obtain Θ ⊢ ((η, ∆, H, ν, ⊥), s′1 ; s′2 ) (ηs′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ), where Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ) ⇒c (ηs′ , ∆′ , H ′ , ν ′ , ⊥) and Θ ⊢ ((η ′ , ∆′ , H ′ , ν ′ , ⊥), s2 ) ⇒c (ηs′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ). Using induction on s1 we obtain Θ ⊢ ((η, ∆, H, ν, ⊥), s′1 ) ⇒c (ηs′ , ∆′ , H ′ , ν ′ , ⊥). Now, we can also apply induction on s2 to get Θ ⊢ ((η ′ , ∆′ , H ′ , ν ′ , ⊥), s′2 ) ⇒c (ηs′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ). Thus, we can apply the concrete (composition) rule on the results of the rewriting to obtain Θ ⊢ ((η, ∆, H, ν, ⊥), s′1 ; s′2 ) ⇒c (ηs′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ) This shows that evaluating the original statement and the rewritten version both produce the same environment. Finally, observe that Lemma 6.1 naturally hold, thus proving that ∆′ |= (∆s , π). □

Corollary 7.2. Let s be any statement. If s −→γ−wrap s′ Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) then Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) Proof The proof follows directly from Lemma 7.1.

□

8 T R2 : Early-Returns Elimination In this transformation, occurrences of multiple return statements are collapsed into one. In this transformation, occurrences of multiple return statements are collapsed into one. Fig. 8 shows the early-returns rules of the early-returns transformation.

19

The rules define the judgment s −→ret ((πr , µs ), s′ ), where s is the input statement, πr is a path condition indicating whether a return was reached, µs is the return value (⊥ if none), and s′ is the rewritten statement. The return-elimination transformation aims to eliminate early return statements by collapsing all early-return statements into a single return at the end of the rewritten statement. To ensure a sound transformation, two pieces of information must be captured: the path condition πr under which a return was reached, and the returned expression µs . These are propagated by subsequent transformations to preserve the semantics of early returns. The transformation is triggered by the wrapper judgment s −→ret-wrap (πr , ·), which has two cases depending on whether a return was eliminated in s or not. Rule ret-wrap applies when a return was found (µs ̸= ⊥ and πr ̸= f alse), appending a conditional if πr return µs to the rewritten statement s′ . Observe at s′ have no return-statements, and that the subsequent if-statement in (s′ ; if πr then return µs else skip) adds a single return-statement guarded by a summarized condition (πr ) and a summarized returned expression (µs ). Rule ret-wrap-none applies when no return was found, leaving the statement unchanged. Rule ret-return is the base case, handling a return e statement by setting the return path condition πr = true and the return expression µs = e, replacing the statement with skip. For compound control flow, the transformation must collect return information from all reachable sub-statements. Rule ret-if handles conditionals by processing both branches independently and merging their return conditions and expressions using the γ expression. Rule ret-comp similarly processes both s1 and s2 in a sequential composition, collecting return information from each side. In sequential composition, a return may occur in either s1 or s2 . The merged return condition πr∗ is simp(γ (πr , true, πr′ )): if s1 returned then πr∗ is true, otherwise it takes the return condition πr′ collected from rewriting s2 . The merged return expression µ∗s follows the same spirit: it is conditioned on πr , taking µs when s1 returned, and otherwise deferring to µ′s when s2 returned, defaulting to f alse when neither did. The residual guards s′2 with !πr to ensure it executes only if s1 did not return. Finally, the ret-no-op rule covers other types of statements that the transformation does not change/rewrite. The noOpret (s) is defined as

noOpret (x := e) = true − noOpret (invoke(x, z, γ, → y )) = true noOpret (get f ield(x, z, f )) = true noOpret (put f ield(z, f, e)) = true noOpret (skip) = true noOpret (s) = f alse otherwise The transformation also defines the simp function which simplifies γ expressions by collapsing degenerate cases: it returns ⊥ when both branches are ⊥, and f alse when both branches are f alse, avoiding unnecessary symbolic branching in the collected return environment.

20

8.1 Early Returns Elimination is Sound Lemma 8.1 (Early Returns Recursive Judgment is Sound). If ∆ |= (∆s , π ) Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) s −→ret ((πr , µs ), s′ ) Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ )

then η ′′ = η ′ , ∆′′ = ∆′ , H ′′ = H ′ , ν ′′ = ν ′ µ′′ = ⊥ µ′ ̸= ⊥ =⇒ ∆′′ ⊢ µs ⇝c µ′ µ′ ̸= ⊥ iff ∆′′ ⊢ πr ⇝c true

(1) (2) (3) (4)

Proof First, let us consider ret-no-op rule. In this case, the rewriting does not change the initial statement, i.e., Θt , ηs , ∆s , Hs , χ, u ⊢ s −→ret ((π, µs ), s), where πr = f alse, µs = ⊥. Here, we will consider the case when s is the assignment statement, i.e., s = x := e, but other statements where noOp ret predicate is valid will follow the same argument. In this case, the concrete semantics will evaluate as Θ ⊢ ((η, ∆, H, ν, µ), x := e) ⇒c (η, ∆[x ← v], H, ν, µ), where ∆ ⊢ e ⇝c v. Here, we have that η ′ = η ′′ = η, H ′ = H ′′ = H, ν ′ = ν ′′ = ν, µ′ = µ′′ = µ = ⊥, and ∆′ = ∆[x ← v] = ∆′′ (conclusion 1&2). Since we have µ′ = µ = ⊥, then conclusion 3 holds trivially. Finally, we know that πr = f alse, which satisfies conclusion 4. Now consider the ret-return rule. Here we have return e −→ret ((πr , µs ), skip), such that πr = true and µs = e. In this case, the concrete semantics of the original statement will evaluate as Θ ⊢ ((η, ∆, H, ν, µ), return e) ⇒c (η, ∆, H, ν, v), where ∆ ⊢ e ⇝c v. On the other hand, evaluating concretely the rewritten statement, we obtain Θ ⊢ ((η, ∆, H, ν, µ), skip) ⇒c (η, ∆, H, ν, µ). Here, we have that η ′ = η ′′ = η, H ′ = H ′′ = H, ν ′ = ν ′′ = ν, µ′ = v, µ′′ = ⊥, and ∆′ = ∆′′ = ∆ (conclusion 1&2). Also, we have that µs = e. Now observe that, we have µ′ ̸= ⊥ and that ∆′′ ⊢ e ⇝c v , where v = µ′ (conclusion 3). Finally, we have πr = true satisfying conclusion 4. Now consider ret-comp rule, s1 ; s2 −→ret ((πr′ , µ′s ), s′1 ; if (!πr′′ ) then s′2 else skip), where ′′′ ′′′ ′ ′ s1 −→ret ((πr′′ , µ′′ s ), s1 ), s2 −→ret ((πr , µs ), s2 ). ′ ′′ ′′′ ′ ′′′ ′′′ Such that πr = simp(γ(πr , true, πr )), µs = simp(γ(πr′′ , µ′′ s , simp(γ(πr , µs , f alse)))), and that s′ = s′1 ; if (!πr′′ ) then s′2 else skip. Now, there are two cases to execute s = s1 ; s2 concretely depending on whether evaluation of s1 results in executing a return statement or not. That is if Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ), then it can be that µ1 ̸= ⊥ or µ1 = ⊥. If µ1 = ⊥ then the only rule the could apply from the concrete semantics is the composition rule, where Θ ⊢ ((η, ∆, H, ν, µ), s1 ; s2 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ), where Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ), µ1 = ⊥, Θ ⊢ ((η1 , ∆1 , H1 , ν1 , µ1 ), s2 ) ⇒c (η2 , ∆2 , H2 , ν2 , µ2 ). Here we have that η2 = η ′ , ∆2 = ∆′ , H2 = H ′ , ν2 = ν ′ , µ2 = µ′ . We now show that executing the rewritten statement (s′1 ; if (!πr′′ ) then s′2 else skip) must satisfy the conclusions of the lemma. First, we evaluate s′1 , i.e., we have Θ ⊢

21

((η, ∆, H, ν, µ), s′1 ) ⇒c (η1′ , ∆′1 , H1′ , ν1′ , µ′1 ). By applying induction on s1 , we know that η1′ = η1 , ∆′1 = ∆1 , H1′ = H1 , ν1′ = ν1 , µ′1 = ⊥. Also, we have that we have µ1 ̸= ⊥ iff ∆′1 ⊢ πr′′ ⇝c true, thus we can conclude πr′′ cannot be evaluated to true, and since we assume that the rewritten statement has executed to completion, then we can conclude that πr′′ must evaluate to f alse, i.e., ∆′1 ⊢ πr′′ ⇝c f alse. Now, to evaluate if (!πr′′ ) then s′2 else skip we must use the concrete rule if-phi-false, i.e, s′2 must be evaluated. Θ ⊢ ((η1′ , ∆′1 , H1′ , ν1′ , µ′1 ), s′2 ) ⇒c (η2′ , ∆′2 , H2′ , ν2′ , µ′2 ) in this case we have η ′′ = η2′ , ∆′′ = ∆′2 , H ′′ = H2′ , ν ′′ = ν2′ , µ′′ = µ′2 . Then, by induction we get η ′′ = η2′ = η2 = η ′ , ∆′′ = ∆′2 = ∆2 = ∆′ , H ′′ = H2′ = H2 = H ′ , ν ′′ = ν2′ = ν2 = ν ′ (conclusion 1), and µ′′ = µ′2 = ⊥ (conclusion 2). Also we have from the induction that µ2 ̸= ⊥ =⇒ ∆′2 ⊢ µ′′′ s ⇝ c µ2 µ2 ̸= ⊥ iff ∆′2 ⊢ πr′′′ ⇝c true Now, we want to show that this also hold µ2 ̸= ⊥ =⇒ ∆′2 ⊢ µ′s ⇝c µ2 µ2 ̸= ⊥ iff ∆′2 ⊢ πr′ ⇝c true Consider the case where µ′ = µ2 = ⊥, then conclusion 3 holds trivially, i.e., µ2 ̸= ⊥ =⇒ ⇝c µ2 . On the other hand, since πr′ = simp(γ(πr′′ , true, πr′′′ )) = γ(πr′′ , true, πr′′′ ). From Lemma 4.2 that ∆′1 ⊆ ∆′2 , and since we have shown that ∆′1 ⊢ πr′′ ⇝c f alse, then we can conclude that evaluating γ(πr′′ , true, πr′′′ ) in ∆′2 , must results in evaluating πr′′′ , but from induction we just shown that µ2 ̸= ⊥ iff ∆′2 ⊢ πr′′′ ⇝c true holds, which implies that πr′′′ must evaluate in ∆′2 , i.e., µ2 ̸= ⊥ iff ∆′2 ⊢ πr′ ⇝c true (conclusion 4). On the other hand, if µ′ = µ2 ̸= ⊥, then, we can conclude that ∆′2 ⊢ πr′′′ ⇝c true, ′ ′′ ′′ ′′′ ′′′ and ∆′2 ⊢ µ′′′ s ⇝c µ2 . This means that the expression µs = γ(πr , µs , γ(πr , µs , f alse)) will ′′′ ′ ′ reduce, using concrete rules γ-true and γ-false, to evaluating µs in ∆2 , i.e., ∆′2 ⊢ µ′′′ s ⇝c µ (conclusion 3). Similarly, we know that the expression πr′′′ = γ(πr′ , true, πr′′ ), must reduce to true, since by induction, it must be the case that πr′′ evaluated to true in ∆′2 (conclusion 4). Finally, the case where we have µ1 ̸= ⊥, then the concrete rule composition-ret will apply. Here we have that η ′ = η1 , ∆′ = ∆1 , H ′ = H1 , ν ′ = ν1 , µ′ = µ1 . Similarly we have η ′′ = η1′ , ∆′′ = ∆′1 , H ′′ = H1′ , ν ′′ = ν1′ , µ′′ = µ′1 . By induction on s1 , we know that it must be that ∆′2 ⊢ µ′s

µ1 ̸= ⊥ =⇒ ∆′1 ⊢ µ′′ s ⇝ c µ1 µ1 ̸= ⊥ iff ∆′1 ⊢ πr′′ ⇝c true since we have that µ1 ̸= ⊥ then πr′′ must evaluate to true in ∆′1 . Now evaluating the second part of s′ , i.e., the if-statement if (!πr′′ ) then s′2 else skip, must result in evaluating the skip statement, yielding the same concrete state, i.e., Θ ⊢ ((η1′ , ∆′1 , H1′ , ν1′ , µ′1 ), if (!πr′′ ) then s′2 else skip) ⇒c (η1′ , ∆′1 , H1′ , ν1′ , µ′1 ) Which from induction satisfies the conclusions of the lemma. Now, consider the ret-if rule, we have, if e then s1 else s2 −→ret ((πr′ , µ′s ), if e then s′1 else s′2 ), ′ ′′′ ′′′ ′ ′ ′′ ′′′ ′ where s1 −→ret ((πr′′ , µ′′ s ), s1 ), s2 −→ret ((πr , µs ), s2 ), πr = simp(γ(e, πr , πr ), µs = ′′ ′′′ simp(γ(e, µs , µs )). There are two cases for evaluating the if-statement depending on whether the expression e evaluates to true or not. We will show the proof when e evaluates to true, but the other case follows similar reasoning. Thus, here we have ∆ ⊢ e ⇝c true, the concrete semantics

22

must evaluate s1 , Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ). In this case, there are two concrete evaluation rules that can apply: if-phi-true or if-phi-true-ret, depending on whether µ1 = ⊥ or not. Since no phi-assignment case exist in the early return grammar, then we know that η = η ′ , ∆1 = ∆′ , H1 = H ′ , ν1 = ν ′ , µ1 = µ′ Now, executing the re-written statement if e then s′1 else s′2 , must initially start by evaluating e, since e has not changed by the rewritten, and is evaluated in the same environment Delta, then it must evaluate to the same value, true. Consequently, s′1 is be evaluated next, that is Θ ⊢ ((η, ∆, H, ν, µ), s′1 ) ⇒c (η1′ , ∆′1 , H1′ , ν1′ , µ′1 ). Here we have that η ′′ = η1′ , ∆′′ = ∆′1 , H ′′ = H1′ , ν ′′ = ν1′ , µ′′ = µ′1 . By induction, we know that η ′′ = η1′ = η1 = η ′ , ∆′′ = ∆′1 = ∆1 = ∆′ , H ′′ = H1′ = H1 == H ′ , ν ′′ = ν1′ = ν1 = ν ′ (conclusion 1) and µ′′ = ⊥ (conclusion 2). Also, by the induction we have µ1 ̸= ⊥ =⇒ ∆′1 ⊢ µ′′ s ⇝c µ1 µ1 ̸= ⊥ iff ∆′1 ⊢ πr′′ ⇝c true . At this point we want to show that µ1 ̸= ⊥ =⇒ ∆′1 ⊢ µ′s ⇝c µ1 µ1 ̸= ⊥ iff ∆′1 ⊢ πr′ ⇝c true . In the case where µ1 = ⊥, µ1 ̸= ⊥ =⇒ ∆′1 ⊢ µ′s ⇝c µ1 holds trivially. Also, we know that if µ1 = ⊥, then πr′′ cannot evaluate to true, that is ∆′1 ⊢ πr′′ ⇝c true cannot happen. From Lemma 4.2, we have that ∆ ⊆ ∆′1 , which implies that the expression e must still evaluate to true when evaluated in ∆′1 . Now evaluating πr′ = simp(γ(e, πr′′ , πr′′′ ) in ∆′1 must reduce to evaluating since πr′′ which we have shown that it cannot evaluate to true (conclusion 4). On the other hand consider the case where µ1 ̸= ⊥. Here, evaluating µ′s defined as ′′′ ′′ µ′s = simp(γ(e, µ′′ s , µs )), must reduce to evaluating µs but we have already shown by the ′ ′′ ′ induction that µ1 ̸= ⊥ =⇒ ∆1 ⊢ µs ⇝c µ (conclusion 3). Similarly, evaluating πr′ in ∆′1 , defined as πr′ = simp(γ(e, πr′′ , πr′′′ ), which reduces to evaluating πr′′ , which we have already shown that it holds by the induction (conclusion 4). □

Theorem 8.2. Let s be a statement. If Θ ⊢ ((η, ∆, H, µ), s) ⇒c (η ′ , ∆′ , H ′ , µ′ ) s −→ret−wrap (πr , s′ ) Θ ⊢ ((η, ∆, H, µ), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , µ′′ ) then η ′′ = η ′ , ∆′′ = ∆′ , H ′′ = H ′ , ν ′′ = ν ′ , µ′′ = µ′

8.2 Properties The early-return elimination transformation assumes all the guarantees by the γ creation transformation, and it provides the following guarantees. Given s −→ret−wrap (πr , ŝ), this transformation guarantees the following properties 23

• Rewritten Statement ŝ satisfies the SSA (property A.1). Proof This is clear since none of the rules in Fig. 8 modify assignments within generalized assignment statements, update local/heap mappings, or introduce new variables. □

• Rewritten statement always has at most a single return within an if-statement (Property A.13). • If the original statement s has a return statement, then there must be a valid returncondition, and the rewritten statement must be of a specific form (Property A.14). • Return condition (πr ) is true on all return paths (Property A.15). Proof This can be directly be shown by applying the recursive theorem of the ret judgment. □

9 T R3 : Remove Final Return

integer n ∈ Z subscript j ∈ Z+ ⊎ {⊥} identif ier a, b, c ∈ Id class c ∈ C signature g ∈ G f ield f ∈ F ref erence r ∈ R

literal v ::= n | true | f alse | null var x, y, i, o, t ::= (a, j ) → − method m ::= ( x .s) unaryOp ::= − |! binaryOp ⋄ ::= + | − | ∗ | ÷ | & | bitwise − or | ⊕ | % |==|! =|≤|≥| && | logical-or |> |< |≪|≫ exp e ::= v | x | e1 ⋄ e2 | e | γ (e, e1 , e2 ) simple-ref. z ::= r | x − stmt s ::= s1 ; s2 | x := e | skip | if e then s1 else s2 | invoke(x, z, g, → y ) | return e put f ield(z, f, e) | get f ield(x, z, f ) | new(x, c)

Figure 9: Remove Final Return to-grammar

The early-return elimination transformation does three things: it captures the return condition πr and the return expression µs into the environment, and appends a single return statement guarded by πr of the form if πr then return µs else skip, replacing all early returns. The final-return elimination transformation then removes this guarded return statement, as πr and µs in the environment already capture sufficient information about the return for subsequent transformations. Fig. 10 shows the two rules of this transformation. Rule final-noop handles the case where πr = f alse, indicating that no early return was eliminated, and thus no guarded return is present; the statement is left unchanged and µs is set to ⊥. Rule final-ret handles the case where πr ̸= f alse, using pattern matching to identify 24

the guarded if πr then return e else skip appended by the early-return elimination transformation, stripping it from the statement and recording µs = e.

9.1 Remove Final Return Transformation is Sound ( Let us define evalReturn(∆, πr , µs ) ≜

v if (∆, πr ) ⇝c true ∧ (∆, µs ) ⇝c v ⊥ otherwise

Lemma 9.1 (evalReturn is not changed by extension of the environment). evalReturn(∆, πr , µs ) = evalReturn(∆′ , πr , µs ) where ∆ ⊆ ∆′ Proof

□

Corollary 9.2 (Remove final-return transformation is sound). If for any statement s and a rewriting state (Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I, O, T ), u), Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) s −→remove−ret (µs , s′ ) Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ )

then η ′′ = η ′ , ∆′′ = ∆′ , H ′′ = H ′ , ν ′′ = ν ′ , µ′′ = ⊥ µ′ = evalReturn(∆′′ , πr , µs ) Proof Since there are only two rewrite rules that can apply, we will proceed with our proof by considering the two possible cases for πr : when it is the formula f alse, and when it is not. First, consider the case when πr is f alse. According to assumed early-return property(Property A.15), µ′ must be ⊥, which also means that s contains no return statements. Otherwise, if a control flow existed with µ′ ̸= ⊥ but πr = f alse, this would violate the earlyreturn (Property A.15). Thus, s cannot be of the form s′′ ; if πr then return e else skip, and the final-noop rule applies without modifying s. Hence, s′ = s and µ′ = ⊥. Consequently, executing s′ yields the same state, i.e., η ′′ = η ′ , ∆′′ = ∆′ , H ′′ = H ′ , ν ′′ = ν ′ , and µ′′ = µ = ⊥ (conclusion 2). Finally, in this case, the second branch of evalReturn applies, giving evalReturn(∆′′ , πr , µ′s ) = ⊥ = µ′ (conclusion 3). The second case is when πr ̸= f alse. From the assumed property of early-returns transformation (Property A.14), s must be of the form s = s′′ ; if πr then return e else skip Executing s concretely first applies composition, evaluating s′′ as Θ ⊢ ((η, ∆, H, ν, µ), s′′ ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ), where µ′′′ = ⊥, followed by evaluating the conditional using either if-phi-true or if-phi-false, depending on πr . If πr evaluates to true, we apply if-phi-true (since ¬hasReturn(s′′ ), if-phi-true-ret cannot apply), yielding Θ ⊢ ((η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ = ⊥), if πr then return e else skip) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ4 )

25

where η ′ = η ′′′ , ∆′ = ∆′′′ , H ′ = H ′′′ , ν ′ = ν ′′′ , and µ′ = µ4 = v, with ∆′′′ ⊢ e ⇝c v. Since πr ̸= f alse and s = s′′ ; if πr then return e else skip, the final-ret rule applies, giving s′ = s′′ and µs = e. Executing s′ gives Θ ⊢ ((η, ∆, H, ν, µ), s′′ ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ), with η ′′ = η ′′′ = η ′ , ∆′′ = ∆′′′ = ∆′ , H ′′ = H ′′′ = H ′ , ν ′′ = ν ′′′ = ν ′ , and µ′′′ = µ = ⊥ (conclusion 2). Because πr ̸= f alse, the first condition of evalReturn applies. Since ∆′′ = ∆′′′ , we have ∆′′′ ⊢ e ⇝c v1 with v1 = v = µ4 = µ (conclusion 3). If, instead, πr evaluates to f alse, if-phi-false applies, executing skip and yielding Θ ⊢ ((η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ = ⊥), if πr then return e else skip) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ4 ) such that η ′ = η ′′′ , ∆′ = ∆′′′ , H ′ = H ′′′ , ν ′ = ν ′′′ , and µ′′′ = µ4 = ⊥ = µ′ , with ∆′′′ ⊢ πr ⇝c f alse. Executing s′ again yields η ′′ = η ′′′ = η ′ , ∆′′ = ∆′′′ = ∆′ , H ′′ = H ′′′ = H ′ , ν ′′ = ν ′′′ = ν ′ , and since ¬hasReturn(s′′ ), µ′′′ = µ = ⊥ (conclusion 2). Finally, because πr = f alse, the second condition of evalReturn applies, giving evalReturn(∆′′ , πr , µs ) = ⊥ = µ′ (conclusion 3). □

9.2 Properties of the Final-Returns Transformation The remove final-return transformation assumes all properties guaranteed by the earlyreturn elimination transformation, and it provide the following guarantees. Given πr ⊢ s −→f inal−wrap (µs , s′ ), we have that

• Rewritten statement s′ satisfies the SSA property (Property A.1). More formally, SSA(s′ ) holds. Proof This is straightforward: since s satisfies the SSA property and none of the rules in Fig. 10 introduce new variables or update existing ones, it follows that isSSA(s′ ). □

• Statement s′ has no return statements (Property A.16). ¬hasReturn(s′ ) is valid.

More formally,

Proof We know that the only case where a return statement can exist in s is when it is of the from s = ŝ; if πr then return e else skip, and that πr ̸= f alse (Property A.14). This means that ŝ cannot contain another return statement because atMostSingleIfReturn(s) would be violated. Therefore, when we can only apply final-ret rule, which removes the enclosed return statement on the then-side, and rewrites the statement s to ŝ, where ŝ = s′ , which we have just shown that it cannot contain a return statement, i.e., ¬hasReturn(s′ ). □

10 T R4 : Renaming Transformation This transformation assigns a unique index to every local variable in the statement s. Specifically, each variable of the form (a, ⊥) is renamed to (a, j ), where j ∈ Z+ , ensuring that distinct occurrences of the same variable across multiple summarizations of s, i.e., within loops or recursive calls, are uniquely distinguished. Fig. 11 shows a snippet of the main renaming rules. The rules define two judgments. The judgment u ⊢ s −→rename s′ rewrites an IR statement s into s′ , where u is the global unique index used to assign fresh version numbers to unversioned variables. The wrapper judgment I, O ⊢ ((πr , µs , T, u), s) −→rename-wrap ((µ′s , πr′ , T ′ , u′ ), s′ ) is 26

the entry point of the transformation, triggering the rename judgment on s. Here, I and O are the sets of input and output variables, πr and µs are the early-return path condition and symbolic return expression, and T is the set of temporary variables. Their primed counterparts πr′ , µ′s , T ′ , and u′ reflect their updated values after the rewriting. For example, rule rename-var renames a variable x to x′ by applying uniqueu (x), which assigns the current counter u as the version index if x has not yet been renamed, i.e., if it is of the form (a, ⊥). If x already carries a non-⊥ index, uniqueu leaves it unchanged, as captured by the side condition j ̸= ⊥ in the definition of uniqueu at the top of Fig. 11. This behavior is deliberate: it allows e 7→rename e′ to be applied over partially renamed statements, skipping variables that have already been versioned and acting only on those that remain unversioned, i.e., those carrying ⊥. Rule rename-unaryOp propagates the renaming into the operand e, deriving u ⊢ e 7→rename e′ in the premise, and reconstructs e′ around the renamed result. The rule does not itself rename anything directly but serves as a structural rule that drives the renaming relation into sub-expressions. Rules for other expression forms, including binary operators and γ -expressions, are omitted from Fig. 11 for brevity, but follow the same pattern of propagating renaming onto their constituent sub-expressions. The renaming transformation is propagated structurally over statements. Rule rename-assign handles assignment by renaming both the right-hand side expression e and the left-hand side variable x independently, producing the renamed assignment x′ := e′ . Rule rename-comp handles sequential composition by propagating the renaming relation into each sub-statement independently under the same counter u, yielding s′1 ; s′2 . Other statement forms follow the same pattern. Rules for conditionals, rename-putfield, and rename-invoke, etc., all propagate renaming into their sub-statements and invoke renaming on their composing expressions. Notably, rename-invoke renames the variables and expressions appearing in the call site without inlining the body of the invoked method; the inlining of method bodies is deferred to a dedicated later transformation. Finally, the rule rename-wrap extends the renaming transformation to environment variables that live outside the statement but must be consistently renamed to match their new names within it ( πr and µs are renamed to πr′ and µ′s ). Using the same counter u′ = u + 1, it renames the input/output sets I , O, and the temporary set T via uniqueu′ , and applies u′ ⊢ s −→rename s′ to the statement, ensuring all unversioned variables across both the environment and the statement receive the same index. To preserve the external interface of s, the rewritten statement s′′ wraps s′ with assignments that bind the old input names to their renamed counterparts before s′ , and bind the renamed output variables back to the old output names after, ensuring s′′ exposes the same input/output interface as s.

10.1 Renaming Transformation is Sound To show the soundness of this transformation, we first show the soundness of the expression judgment, and follow that up with our usual discussion about the soundness of the statement recursive judgment and then the wrapper judgment. 27

Lemma 10.1 (Expression Renaming is Sound). Let uniqueu (∆) = {(uniqueu (x), ∆(x)) | x ∈ Dom(∆)}, then for any concrete expression e and for any integer u, if ∆ ⊢ e ⇝c v

∧

u ⊢ e 7→rename e′

then, we have uniqueu (∆) ⊢ e′ ⇝c v That is, evaluating the rewritten expression will result to the same value v that is obtained when evaluating the original expression, if and only if the evaluation used the local variable mapping from uniqueu (∆). Proof We will proceed by induction on the judgment u ⊢ e 7→rename e′ . First, observe that the lemma proves trivially on rename-val rule, since there are no variables contained within values, and thus no rewriting is done. Now, consider the rename-var rule, we have, u ⊢ x 7→rename x′ , where e′ = x′ = uniqueu (x) = (x, u). Applying the var rule in the concrete semantics, we obtain ∆ ⊢ x ⇝c v, such that ∆(x) = v. Now evaluating the rewritten expression (uniqueu (∆))(x, u) = v, directly from the definition of the unique function, thus, we have uniqueu (∆) ⊢ (x, u) ⇝c v. Consider the rename-binaryOp rule. the rewriting will produce u ⊢ e1 ⋄e2 7→rename e′1 ⋄e′2 , where u ⊢ e1 7→rename e′1 , u ⊢ e2 7→rename e′2 . Evaluating concretely the binary operation expression, we get ∆ ⊢ e1 ⋄ e2 ⇝c v3 , where ∆ ⊢ e1 ⇝c v1 , ∆ ⊢ e2 ⇝c v2 , v1 ⋄ v2 = v3 . We know by induction on e1 , and e2 that uniqueu (∆1 ) ⊢ e′1 ⇝c v1 , uniqueu (∆2 ) ⊢ e′2 ⇝c v2 . Observe that we have uniqueu (∆1 ) = uniqueu (∆2 ) = uniqueu (∆) = {(uniqueu (x), ∆(x)) | x ∈ Dom(∆)}. The reason that they are the same is that the expression judgment does not change in the state ∆ when evaluating expressions, as expressions as per the definition do not have side effects on the environment. Now, applying the binary-Op on the reduced values, we obtain uniqueu (∆) ⊢ e′1 ⋄ e′2 ⇝c v. The same argument also follows for the rewriting of rename-unaryOp rule. Now, consider the rename-γ rule, the rewriting will produce u ⊢ γ(e1 , e2 , e3 ) 7→rename γ(e′1 , e′2 , e′3 ), such that u ⊢ e1 7→rename e′1 , u ⊢ e2 7→rename e′2 , u ⊢ e3 7→rename e′3 . There are two rules to evaluate a γ-expression concretely, depending on whether its condition evaluates to true or false. We show the proof when the condition evaluates to true, but the other case follows a very similar argument. Here, evaluating that γ-expression, we get ∆ ⊢ γ(e1 , e2 , e3 ) ⇝c v, such that ∆ ⊢ e1 ⇝c true, ∆ ⊢ e2 ⇝c v, and where e = γ(e1 , e2 , e3 ). By using induction on e1 and e2 , we get uniqueu (∆) ⊢ e′1 ⇝c v1 , uniqueu (∆1 ) ⊢ e′2 ⇝c v2 . Therefore, we can conclude that evaluating γ(e′1 , e′2 , e′3 ) must evaluate to v1 , that is, uniqueu (∆) ⊢ γ(e′1 , e′2 , e′3 ) ⇝c v1 . □

Now, we define the lemma for statements, and then discuss its proof.

Lemma 10.2 (Recursive statement renaming is sound). Let Let s be any statement and a rewriting state (Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I, O, T ), u), and uniqueu (∆) be defined as uniqueu (∆) = {(uniqueu (x), ∆(x)) | x ∈ Dom(∆)}. Then, if Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

u ⊢ s −→rename s′

28

Then, we have Θ ⊢ ((η, uniqueu (∆), H, ν, µ), s′ ) ⇒c (η ′ , uniqueu (∆′ ), H ′ , ν ′ , µ′ ) Proof First, observe that the rename-skip rule holds trivially as no change to the statement actually happens. Now, consider the rename-assign rule. u ⊢ x := e1 −→rename x′ := e′1 , for some u, where x′ = uniqueu (x) and u ⊢ e 7→rename e′1 . Evaluating, the original statement concretely we get Θ ⊢ ((η, ∆, H, ν, µ), x := e1 ) ⇒c (η, ∆′ , H, ν, µ), where ∆′ = ∆[x ← v], ∆ ⊢ e1 ⇝c v. Observe that using the expression lemma 10.1, we have e′1 evaluating to the same value v when evaluated on the unique local mapping, i.e., uniqueu (∆) ⊢ e′1 ⇝c v. Now, evaluating the rewritten statement on the unique local mapping, we have Θ ⊢ ((η, uniqueu (∆), H, ν, µ), x′ := e′ ) ⇒c (η, ∆′′ , H, ν, µ), where ∆′′ = uniqueu (∆)[x′ ← v], and x′ = uniqueu (x) = (x, u). Now observe that, ∆′′ = uniqueu (∆)[x′ ← v] = uniqueu (∆′ ). This observation follows directly from applying the uniqueu function on ∆′ , and from observing that ∆′ (x) = uniqueu (∆)(x′ ). Next, consider the rename-comp rule. Applying the rewriting we get u ⊢ s1 ; s2 −→rename s′1 ; s′2 , for some u, where u ⊢ s1 −→rename s′1 , u ⊢ s2 −→rename s′2 . There are two cases for executing a composition statement in the concrete semantics, either s1 has a return control flow (composition-ret rule), or not (composition rule). But, recall by from the previous transformation (remove final-returns), it is guaranteed that return statements are guaranteed to not exist in s A.16 that also enforced by the grammar of the renaming transformation. This assumption is safe to assume because the renaming transformation always happens after the remove final-return transformation, which ensures that all return statements are removed from s, while capturing the semantics and the conditions of the returns within the rewriting environment variables µs , and πr . Therefore, since s1 cannot contain a return statement, we can apply the composition rule from the concrete semantics to get Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ), and Θ ⊢ ((η1 , ∆1 , H1 , ν1 , µ), s2 ) ⇒c (η2 , ∆2 , H2 , ν2 , µ). Observe here that the concrete execution of s2 also does not change the return expression µ, again because s2 cannot have a return statement, also by the same guaranteed Property A.16. Using induction on s1 we get Θ ⊢ ((η, uniqueu (∆), H, ν, µ), s′1 ) ⇒c (η1 , uniqueu (∆1 ), H1 , ν1 , µ). Using induction on s2 we get Θ ⊢ (η1 , uniqueu (∆1 ), H1 , ν1 , µ), s′2 ) ⇒c (η2 , uniqueu (∆2 ), H2 , ν2 , µ). ⇒c Applying the composition rule, we get Θ ⊢ (η ′ , uniqueu (∆), H, ν, µ), s′1 ; s′2 ) (η2 , uniqueu (∆2 ), H2 , ν2 , µ). Thus, we arrive to the same state reached when executing the original statement s. −→rename Consider the rename-getfield rule, u ⊢ get f ield(x, z, f ) get f ield(x′ , z ′ , f ), where u ⊢ x 7→rename x′ , and u ⊢ z 7→rename z ′ . Also, we can evaluate the original statement concretely by applying concrete rule get-field to get Θ ⊢ ((η, ∆, H, ν, µ), get f ield(x, z, f )) ⇒c (η, ∆′ , H, ν, µ), where ∆′ = ∆[x ← v], ∆ ⊢ z ⇝c r, v = H(r, f ), and r ∈ R. Now, we can apply the expression lemma to get uniqueu (∆) ⊢ z ′ ⇝c r. This means that the same value will be looked up from the Heap, i.e., v = H(r, f ). Now we can apply the get-field rule to get Θ ⊢ ((η, uniqueu (∆), H, µ), get f ield(x′ , z ′ , f )) ⇒c (η, ∆′′ , H, µ), where ′′ ′ ′ ∆ = uniqueu (∆)[x ← v]. Now, observe that ∆(z) = uniqueu (∆)(z ) following from the definition of uniqueu (∆). This implies that uniqueu (∆[x ← v]) = uniqueu (∆)[x′ ← v] = uniqueu (∆)[uniqueu (x) ← v]. That is, updating the mapping of the variable x, then renaming it using the uniqueu function, is the same as, renaming the variable then updating its mapping. To see how this is possible, let (x, v ′ ) be the mapping of x in ∆. Then, ∆[x ← v],

29

will result in updating the (x, v ′ ) mapping with (x, v) mapping. Now, applying uniqueu , i.e., uniqueu (∆[x ← v]), will replace the pervious x mapping with ((x, u), v). On the other hand, uniqueu (∆), will result in replacing (x, v ′ ) definition with ((x, u), v ′ ) in the mapping. Then, uniqueu (∆)[x′ ← v], will update the ((x, u), v ′ ) mapping to ((x, u), v). Thus, we we have that Θ ⊢ ((η, uniqueu (∆), H, µ), get f ield(x′ , z ′ , f )) ⇒c (η, uniqueu (∆)[x′ ← v], H, µ). Consider the rename-putfield rule, u ⊢ put f ield(z, f, e) −→rename put f ield(z ′ , f, e′ ), where u ⊢ e 7→rename e′ , and u ⊢ z 7→rename z ′ . Also, applying put-field, we get Θ ⊢ ((η, ∆, H, µ), put f ield(z, f, e)) ⇒c (η, ∆, H ′ , µ), where H ′ = H[(r, f ) ← v],∆ ⊢ z ⇝c r, r ∈ R, and ∆ ⊢ e ⇝c v. We know from the expression lemma that uniqueu (∆) ⊢ e′ ⇝c v, and similarly that, uniqueu (∆) ⊢ z ′ ⇝c r. Now, if we evaluate the rewritten statement we get Θ ⊢ ((η, uniqueu (∆), H, µ), put f ield(z ′ , f, e′ )) ⇒c (η, uniqueu (∆), H ′′ , µ), where H ′′ = H[(r, f ) ← v] = H ′ . → Consider the rename-invoke rule, we get u ⊢ (invoke(x, z, g, − y )) −→rename − → − →′ − → ′ ′ ′ ′ ′ (invoke(z , x , g, y )), u ⊢ x 7→ x , u ⊢ z 7→ z , and u ⊢ y 7→ y rename

rename

rename

(expanding uniqueu notation to work for a vector of expressions). We also have by applying → invoke concrete rule that, Θ ⊢ ((η, ∆, H, ν, µ), invoke(x, z, g, − y )) ⇒c (η ′′ , ∆′ , H ′′ , ν ′′ , µ′ ), − → − → where ∆′ = ∆[x ← − µ′′ ], µ′ = ⊥, ∆(z) ∈ R, method( y ′ .s′ ) = Θ(η(∆(z)), g), v ′ = → ∆(− y ) (here we are overloading lookup to work over a vector of variables), and Θ ⊢ − → − → ((η, {( y ′ , v ′ )}, H, ν, ⊥), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ). In this case, we have that η ′ = η ′′ , ∆′ = ∆[x ← − µ′′ ], H ′′ = H ′ , ν ′ = ν ′′ , µ′ = µ = ⊥. Observe here that although we initially assumed s to not contain a return statement, this condition is not valid for s′ , because s′ exists in Θ which by the concrete property A.3 must have a return statement. This means, we cannot use the induction hypothesis on s′ , instead we show that by executing this statement s′ in either case will result in the same state. From the expression lemma we get − → − → that uniqueu (∆) ⊢ y ′ ⇝c v ′ , and similarly, we have that uniqueu (∆) ⊢ z ⇝c r. We also know from the definition of uniqueu (∆) that if z is a variable, then it must be that ∆(z) = uniqueu (∆)(z ′ ). This implies that the same method, is looked up and pulled from − → Θ, that is Θ(η(uniqueu (∆(z))), g) = method( y ′ .s′ ). Observe that in this case, we have that − →′ − →′ Θ ⊢ ((η, {( y , v )}, H, µ), s′ ) ⇒c (η ′ , ∆′ , H ′ , µ′ ). Finally, observe that, (η ′ , uniqueu (∆[x ← − µ′ ]), H ′ , µ) = (η ′ , uniqueu (∆)[x′ ← − µ′ ], H ′ , µ), again using the definition uniqueu (∆). Finally, consider the rename-if rule. Observe that here by the guarantee from the γtransformation, we have no ϕ-expressions can exist in s (Property A.12). This means that if-statements that reaches the this transformation, must have an empty list of ϕ-statements. Thus, in the coming proof we discuss the correctness of the if-statements that do not any ϕ−expressions. Applying the rewriting we get u ⊢ (if e then s1 else s2 ) −→rename (if e′ then s′1 else s′2 ), where u ⊢ e 7→rename e′ , u ⊢ s1 −→rename s′1 , and u ⊢ s2 −→rename s′2 . This statement can execute concretely in four cases: when the if-condition evaluates to either true or false, and each case may or may not involve encountering a return statement in the corresponding branch, the return case is excluded by remove final-return transformation which guarantee (Property A.16). We will show the proof when the condition evaluates to true, the other case is similar. First, let us consider the case where the if-condition evaluates to true and we know that no return statement is encountered in s1 . Then, we can apply if-phi-true to get Θ ⊢ ((η, ∆, H, ν, µ), if e then s1 else s2 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ), where ∆ ⊢ e ⇝c true, Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ), again here µ = µ′ = ⊥ from Property A.16. Now, using the expression lemma we get Θ ⊢ (uniqueu (∆), e′ ) ⇝c true. Also, using induction

30

on s1 , we get ⊢ ((η, uniqueu (∆), H, ν, µ), s′1 ) ⇒c (η ′ , uniqueu (∆′ ), H ′ , ν ′ , µ). Thus, evaluating the rewritten statement, we get Θ ⊢ ((η, uniqueu (∆), H, ν, µ), if e′ then s′1 else s′2 ⇒c (η ′ , uniqueu (∆′ ), H ′ , ν ′ , µ′ ), which is what we wanted to show. □

Finally, we prove the rename theorem for the rename-wrap rule.

Theorem 10.3 (Renaming Transformation is Sound). For any statement s. If Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

I, O ⊢ ((πr , µs , T, u), s) −→rename−wrap (µ′s , πr′ , T ′′ , u′ ), s′′ ) then Θ ⊢ ((η, ∆, H, ν, µ), s′′ ) ⇒c (η ′ , ∆′′ , H ′ , ν ′ , µ′ )

∀o ∈ O, ∆′ (o) = ∆′′ (o) evalReturn(∆′ , πr , µs ) = evalReturn(∆′′ , πr′ , µ′s ) ∀i ∈ I, ∆(i) = ∆′ (i) = ∆′′ (i) Proof Here, the rename-wrap rule we get I, O ⊢ ((πr , µs , T, u), s) −→rename−wrap (µ′s , πr′ , T ′′ , u′ ), s′′ ), where u′ = u + 1, s′′ = (i1 , u′ ) := i1 ; . . . ; (in , u′ ) := in ; s′ ; o1 := (o1 , u′ ); . . . ; om := (om , u′ );, u′ ⊢ µs 7→rename µ′s , u′ ⊢ πr 7→rename πr′ , T ′′ = (I ′ ∪ O′ ∪ T ′ ) and where s′ , is obtained from u′ ⊢ s −→rename s′ . Also, we know that executing s concretely we get, Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ). Then, we want to show that Θ ⊢ ((η, ∆, H, ν, µ), s′′ ) ⇒c (η ′ , ∆′′ , H ′ , ν ′ , µ′ ), such that ∀o ∈ O, ∆′ (o) = ∆′′ (o). There are three parts to prove this theorem. First, observe that using the statement lemma (Lemma 10.2) on s′ we know that Θ ⊢ ((η, uniqueu′ (∆), H, ν, µ), s′ ) ⇒c (η ′ , uniqueu′ (∆′ ), H ′ , ν ′ , µ′ ) such that uniqueu′ (∆) = {(uniqueu′ (x), ∆(x)) | x ∈ Dom(∆)} This implies that for the subset of output variables O, we can find a matching mapping values of their unique new name, that is ∀o ∈ O, ∆′ (o) = (uniqueu′ (∆′ ))(o, u′ ), and similarly for input variables i ∈ I, i.e., ∀i ∈ I, ∆′ (i) = (uniqueu′ (∆′ ))(i, u′ ), Second, observe that input assignments within s′′ does not change the value of input values for s, i.e., there are no def-statements that are re-defining variables in I. Also, observe that executing the first assignment, for example, would result in Θ ⊢ ˆ H, ν, µ), where ∆ ˆ = ∆[(i1 , u′ ) ← ∆(i1 )] = ((η, ∆, H, ν, µ), (i1 , u′ ) := i1 ) ⇒c (η, ∆, ∆[uniqueu′ (i1 ) ← ∆(i1 )]. More generally, the local variable mapping we will obtain after executing all assignment statement but before executing s′ will be of the form ∆[uniqueu′ (i1 ) ← ∆(i1 )] . . . [uniqueu′ (in ) ← ∆(in )]. Since we know that uniqueu′ (i) must have been encounˆ tered for any i, and thus is already part of Dom(∆′ ). Also, it is clear that ∆(unique u′ (i)) = ˆ ∆(i). That implies that it must be that Θ ⊢ ((η, ∆, H, ν, µ), (i1 , u′ ) := i1 ; . . . ; (in , u′ ) := in ; s′ ) ⇒c (η ′ , (uniqueu′ (∆′ )), H ′ , ν ′ , µ′ ). Then, evaluating the remaining parts of s′′ , Θ ⊢ ((η ′ , (uniqueu′ (∆′ )), H ′ , ν ′ , µ′ ), (o1 := (o1 , u′ ); . . . ; om := (om , u′ )) ⇒c (η ′ , (uniqueu′ (∆′ ))∪ {(o1 , v1 ), . . . , (om , vm )}, H ′ , ν ′ , µ′ ), where we have that v1 = (uniqueu′ (∆′ ))(o1 , u′ ), . . . , vn = (uniqueu′ (∆′ ))(on , u′ ). Let ∆′′ = (uniqueu′ (∆′ )) ∪ {(o1 , v1 ), . . . , (om , vm )}, then using the above two components we know that it must be the case that ∀o ∈ O, ∆′ (o) = ∆′′ (o).

31

To show the third conclusion of the theorem, we first start by showing that πr , and πr′ are semantically the same, and similarly for µs , and µ′s . From the soundness of the expression lemma 10.1, we know that if ∆′ ⊢ µs ⇝c v ∧ u′ ⊢ µs 7→rename µ′s , then we have uniqueu′ (∆′ ) ⊢ µ′s ⇝c v. Observe here that we have just shown that uniqueu′ (∆′ ) ⊆ ∆′′ , thus we can conclude that ∆′ ⊢ µ′s ⇝c v. Same argument applies for πr and πr′ . Then, we have two cases ∆′ ⊢ πr ⇝c true or not. First, consider the case where πr does not evaluate to true. Then, evalReturn(∆′ , πr , µs ) = ⊥. And we have just shown that πr′ and has a similar evaluation in ∆′′ , thus we get evalReturn(∆′′ , πr′ , µ′s ) = ⊥, so they are equal. Now, consider the second case where πr evaluates to true ∆′ ⊢ πr ⇝c true. Let v be the evaluation of µs , ∆′ ⊢ µs ⇝c v. Then, evalReturn(∆′ , πr , µs ) = v. But again, we have shown that both πr′ and µ′s will evaluate to the same values in ∆′′ , that is ∆′′ ⊢ πr′ ⇝c true, and ∆′′ ⊢ µ′s ⇝c v. Then, evalReturn must evaluate to the same value v, i.e., evalReturn(∆′′ , πr′ , µ′s ) = v = evalReturn(∆′ , πr , µs ), which is what we want to prove. Finally, we show that ∀i ∈ I., ∆(i) = ∆′ (i) = ∆′′ (i). Since i ∈ I, it follows that i ∈ Dom(∆), and because s is in SSA form (i.e., isSSA(s)), no variable in ∆ can be modified during the execution of s. Therefore, ∀i ∈ I., ∆(i) = ∆′ (i). Furthermore, by Guarantee A.1, the rewritten statement s′′ is also in generalized SSA form, ensuring that no variable in Dom(∆) can be updated during the execution of s′′ . Hence, ∀i ∈ I., ∆(i) = ∆′ (i) = ∆′′ (i), as required. □

Corollary 10.4. Let s be any statement such that If Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) I, O ⊢ ((πr , µs , T, u), s) −→rename−wrap (µ′s , πr′ , T ′′ , u′ ), s′′ ) s′′ = i′1 := i1 ; ..; i′n := in ; s′ ; o1 := o′1 ; ..; om := o′m ; then ∆′′ = ∆[i′1 ← ∆(i1 ) . . . i′n ← ∆(in )] Θ ⊢ ((η, ∆′′ , H, ν, µ), s′ ) ⇒c (η ′ , ∆′′′ , H ′ , ν ′ , µ′ ) ∆′′′ (o′1 ) = ∆′ (o1 ) ∧ · · · ∧ ∆′′′ (o′m ) = ∆′ (om ) Proof From the renaming theorem, we know that Θ ⊢ ((η, ∆, H, ν, µ), s′′ ) ⇒c (η ′ , ∆′′ , H ′ , ν ′ , µ′ ) ∧ ∀o ∈ O, ∆′ (o) = ∆′′ (o). Now, observe that the state in which s′ executes must be of the form ∆[i′1 ← ∆(i1 ) . . . i′n ← ∆(in )]. This is clear by partially evaluating s′′ , i.e., Θ ⊢ ((η, ∆, H, ν, µ), i′1 := i1 ; ..; i′n := in ) ⇒c (η, ∆[i′1 ← ∆(i1 ) . . . i′n ← ∆(in )], H, ν ′ , µ). Thus, concretely executing s′ in this local mapping must result in the same state, i.e., Θ ⊢ ((η, ∆[i′1 ← ∆(i1 ) . . . i′n ← ∆(in )], H, ν, µ), s′ ; o1 := o′1 ; ..; om := o′m ) ⇒c (η ′ , ∆′′′ , H ′ , ν ′ , µ′ ), and from the renaming theorem we know that out variable mappings must be the same, i.e., □ ∆′′′ (o′1 ) = ∆′ (o1 ) ∧ · · · ∧ ∆′′′ (o′m ) = ∆′ (om ).

10.2 Properties of the Renaming Transformation The renaming transformation assumes all properties guaranteed by earlier transformations (γ creation, early-returns elimination and remove final-returns), and it provides the following guaranteed properties.

32

For any statement s with I, O, T representing the statement input, output, and temporary variables, and u representing unique-count respectively, if (x, n) ∈ (Id, n) is a variable within s′ , such that

I, O ⊢ ((πr , µs , T, u), s) −→rename−wrap (µ′s , πr′ , T ′′ , u′ ), s′′ ) where u′ = u + 1, χ = (I, O, T ), χ′ = (I ′ , O′ , T ′ ), χ′ = uniqueu′ (χ), I = {i1 ..in }, O = {o1 ..om } , u′ ⊢ s −→rename s′ , s′′ = (i1 , u′ ) := i1 ; ..; (in , u′ ) := in ; s′ ; o1 := (o1 , u′ ); ..; om := (om , u′ ); u′ ⊢ µs 7→rename µ′s , u′ ⊢ πr 7→rename πr′ , T ′′ = (I ′ ∪ O′ ∪ T ′ ) then we have

• Rewritten Statement s′′ satisfies the SSA property (Property A.1). More formally, SSN (s′′ ). Proof Let s′′ = (i1 , u′ ) := i1 ; · · · ; (in , u′ ) := in ; s′ ; o1 := (o1 , u′ ); · · · ; om := (om , u′ ). To show that SSA(s′′ ) holds, note first that by the SSA assumed property from the previous transformation (guaranteed property from remove final-returns transformation, Property A.1) we have SSA(s), and since s′ is obtained from s by a systematic renaming, SSA(s′ ) follows. Next, the prefix assignments (ik , u′ ) := ik introduce only fresh variables (ik , u′ ), and since ik ∈ I implies ¬isDef (ik , s) ∧ isU se(ik , s), it follows that ¬isDef ((ik , u′ ), s′′ ) ∧ isU se((ik , u′ ), s′′ ), hence no clashes arise with s′ . Finally, the suffix assignments oj := (oj , u′ ) do not introduce new definitions, because all occurrences of oj have already been renamed to (oj , u′ ) in s′ , and thus they preserve SSA. Therefore, SSA(s′′ ) holds. For the detailed proof, please refer to our technical report [33]. □

• Fresh variables have u + 1 suffices (Property A.17). More formally, (x, ⊥) is in s, then all its occurrences with s′ must have been renamed to (x, u + 1). Proof This is easy to show as by JR assumptions, we know that all variables in s must have a ⊥ index (Property A.19), for example, for an identifier x, its corresponding variable form that appear in s must be (x, ⊥). Next, observe that renaming of variables are done rename-var, which renames all variables to have an index u + 1, i.e., (x, u + 1) from our continued example above. Observe that happens over all expressions in s, following the rules in Fig. 11. Finally, observe that all environments that are carrying variables, i.e., ∆s , πr , χ are also renamed. □

• Old input not in s′ (Property A.18). More formally, Old input does not appear, i.e., is not used in s′ . More formally if (x, j ) ∈ I , then ¬isU se((x, j ), s′ ) Proof This follows directly by structural induction on s. The renaming transformation replaces every variable x in s with a fresh name x′ , yielding a statement s′ containing only renamed variables. Consequently, none of the original variable names, including those in I, appear in s′ . □

• s′′ and s′ are the same if the state for ∆ is set properly. If I, O ⊢ ((πr , µs , T, u), s) −→rename−wrap (µ′s , πr′ , T ′′ , u′ ), s′′ )

33

Θ ⊢ (η, ∆[(i1 , u′ ) ← ∆(i1 ) . . . (in , u′ ) ← ∆(in )], H, µ), s′ ; o1 := (o1 , u′ ); ..; om := (om , u′ )

⇒c (η ′ , ∆′ , H ′ , µ′ ) Θ ⊢ ((η, ∆, H, µ), s′′ ) ⇒c (η ′′ , ∆′′ , H ′′ , µ′′ ) µ=⊥ where

u′ = u + 1, I = {i1 ..in }, O = {o1 ..om }, s′′ = (i1 , u′ ) := i1 ; ..; (in , u′ ) := in ; s′ ; o1 := (o1 , u′ ); ..; om := (om , u′ ) u′ ⊢ ((I, O, T ), µs ) 7→rename ((I ′ , O′ , T ′ ), µ′s ) then

η ′ = η ′′ , ∆′ = ∆′′ , H ′ = H ′′ , µ′ = µ′′ Proof It is clear that to concretely evaluate s′′ , one has to first evaluate the initial sequence of assignment statements, i.e., (i1 , u′ ) := i1 ; ..; (in , u′ ) := in , which will result in, since these assignment statements have no side effects on η, H or µ, then the intermediate state just before evaluating s′ ; o1 := (o1 , u′ ); ..; om := (om , u′ ) would be (η, ∆[(i1 , u′ ) ← ∆(i1 ) . . . (in , u′ ) ← ∆(in )], H, µ). This then implies that indeed the evaluation of the remaining statements,i.e., s′ ; o1 := (o1 , u′ ); ..; om := (om , u′ ) must result in the same state as η ′ , ∆′ , H ′ , µ′ . □

11 T R5 : Input Substitution Transformation The substitution transformation substitutes values of the region’s inputs that are defined in I . Fig. 12, shows a snippet of the rules for the substitution transformation. The rules define two judgments. The judgment ∆s , I ⊢ s −→sub s′ rewrites an IR statement s into s′ by substituting variables with their corresponding values in the symbolic local variable mapping ∆s , where I is the set of input variables whose occurrences drive the substitution. The wrapper judgment ∆s ⊢ ((πr , µs , I ), s) −→sub-wrap ((πr′ , µ′s , I ′ ), s′ ) is the entry point of the transformation, triggering the sub judgment on s and additionally applying the substitution to the early-return path condition πr and symbolic return expression µs , producing their updated counterparts πr′ and µ′s , and updating the input set from I to I ′ . The substitution transformation replaces variables with their corresponding values in ∆s . For expressions, Rule sub-expr directly substitutes each variable occurrence with its mapped value in ∆s . For statements, the transformation propagates substitution over all uses of variables, leaving definitions unchanged. Rule sub-wrap extends the substitution to environment variables that live outside the statement, applying it to the path condition π , the return condition πr , and the return expression µs . Additionally, the wrapper updates the input set I to reflect the free variables in all rewritten expressions, as the previous input variables in I have been replaced by their mapped values in ∆s and are no longer needed as inputs.

Lemma 11.1 (Expression Substitution is Sound). For any concrete expression e, if

34

∆ ⊢ e ⇝c v ∆s , I ⊢ e 7→sub e′

then for any ∆′ such that ∆′ |= (∆s , π ) ∆ ⊆ ∆′

we have ∆′ ⊢ e′ ⇝c v

∀i ∈ I.¬isU se(i, e′ ) Proof We will proceed by induction on the judgment ∆s , I ⊢ e 7→sub e′ . For this proof, let ∆, H represents the concrete variable mapping and the concrete heap, while ∆s , Hs and π represents the symbolic variable mapping, the symbolic heap and the path condition, respectively. Finally, I represents the input variables. Also, we have that (∆′ , H) |= (∆s , Hs , π). First, consider sub-val. Since the rewrite does not modify the value v, and v always evaluates to itself, we trivially have ∆′ ⊢ v ⇝c v. Moreover, v does not perform any lookup in ∆ during evaluation, and ∀i ∈ I.¬isU se(i, v) holds immediately, as v is a val. Next, consider sub-var-triv where e = x and x ∈ / I. In this case, no rewriting occurs, i.e., e = x = e′ . Now, observe that since ∆ ⊆ ∆′ and the fact that (∆′ ) |= (∆s , π), then evaluating x in ∆′ must yield the same value as the value resulting from evaluating it in ∆, i.e., ∆ ⊢ e′ ⇝c v and ∆′ ⊢ e′ ⇝c v (conclusion 1). The second conclusion holds trivially, since x is not an input. Now, consider sub-var, where e = x and x ∈ I, yielding ∆s , I ⊢ x 7→sub e′ with ′ e = ∆s (x). The first conclusion holds trivially from ∆ ⊆ ∆′ and the fact that (∆′ ) |= (∆s , π). The second conclusion holds since we have substituted the value ∆s (x) for x and we have that ∀i ∈ I.∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)), then we can conclude that e′ = ∆s (x) does not use any input variable. Now, consider the sub-binaryOp rule. Let e = e1 ⋄e2 c. We have that ∆s , I ⊢ e1 ⋄e2 c 7→sub e′1 ⋄ e′2 c. On the other hand, concretely evaluating e, we get ∆ ⊢ e1 ⋄ e2 c ⇝c v (using binaryOp), such that ∆ ⊢ e1 ⇝c v1 and ∆ ⊢ e2 ⇝c v2 , and thus v = v1 ⋄ v2 c. By induction on e1 and e2 , we get ∆′ ⊢ e′1 ⇝c v1 and ∆′ ⊢ e′2 ⇝c v2 , where ∀i ∈ I.¬isU se(i, e′1 ) and ∀i ∈ I.¬isU se(i, e′2 ). Thus, applying the binaryOp rule over the evaluation of e′1 and e′2 yields ∆′ ⊢ e′1 ⋄ e′2 c ⇝c v (first conclusion). Also, not that ∀i ∈ I.¬isU se(i, e′1 ⋄ e′2 c), this is because isU se(i, e′1 ⋄ e′2 c) = isU se(i, e′1 ) ∨ isU se(i, e′2 ), since the binary operation does not introduce new variables. The soundness of sub-unaryOp and sub-γ rewriting follows the same recursive argument as sub-binaryOp, differing only in the number of inductive steps: one for unaryOp and three for sub-γ. □

Theorem 11.2 (Statement Recursive Substitution is Sound). Let s be any statement. If Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (ηs , ∆′ , H ′ , ν ′ , µ′ ) ∆s , I ⊢ s −→sub s′ ∀i ∈ I.∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) 35

then for any ∆′′ such that (∆′′ ) |= (∆s , π ) ∆ ⊆ ∆′′ Θ ⊢ ((η, ∆′′ , H, ν, µ), s′ ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ )

Then η ′′′ = η ′ , H ′′′ = H ′ , ν ′′′ = ν ′ , µ′′′ = µ′ ∆′ ⊆ ∆′′′ ∀i ∈ I.¬isU se(i, s′ ) Proof Let ηs , ∆, H, ν, µ, ∆s , Hs , π, I, O, ∆, ∆′′ and s satisfy the premises of the theorem. We will prove this theorem by using structural induction. First, observe that the sub-skip rule does not introduce any change to the rewritten statement. Also, observe that in skip, no state is used/accessed during its evaluation. Therefore, we will have that ∆′′′ = ∆′′ and ∆′ = ∆, and thus, the first and second conclusion hold, trivially. The third conclusion also holds because a skip by definition cannot contain an input variable. In the sub-new case, the statement s is unchanged (s′ = s). Thus, we have that (η ′ , ∆′ , H ′ , ν ′ , µ′ ) be the state from evaluating the original statement, Θ ⊢ ((η, ∆, H, ν, µ), new(x, c)) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ), such that ν ′ = ν + 1, ∆′ = ∆[x ← r], η ′ = η[r ← c], r = freshRef(ν ′ ). Now, let us assume we have ∆′′ such that it satisfies the symbolic state, i.e., (∆′′ ) |= (∆s , π), and ∆ ⊆ ∆′′ . Since, obtaining a new reference is deterministically defined over ν ′ , i.e., r = freshRef(ν ′ ). thus, on evaluating the non-changing rewritten statement s′ in ∆′′ , we get Θ ⊢ ((η, ∆′′ , H, ν, µ), new(x, c)) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ). Here, we also have that r = freshRef(ν ′ ), thus we know that ν ′′′ = ν + 1 = ν ′ , η ′′′ = η[r ← c] = η ′ , H ′′′ = H = H ′ , µ′′′ = µ = µ′ (conclusion 1). Also, we have that the execution of s and s′ introduces exactly one new mapping, the binding x, such that ∆′′′ = ∆′′ [x ← r], and ∆′ = ∆[x ← r], and since we have that ∆ ⊆ ∆′′ , then by transitivity we can conclude that ∆′ ⊆ ∆′′′ (conclusion 2). By the guarantee of previous transformations, we know that SSA(s) most hold (Property A.1), z cannot appear in either ∆ or ∆′′ , since otherwise there would be multiple definitions for z, violating the generalized SSA property; moreover, x ∈ / I because isDef (z, new(x, c)) holds, while I only contains variables i such that isU se(i, s) ∧ ¬isDef (i, s). Thus, we can conclude that ∀i ∈ I. ¬isU se(i, new(x, c)) (conclusion 3). Consider the sub-assign rule. From the concrete semantics, we have Θ ⊢ ((η, ∆, H, ν, µ), x := e) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) by assign, where ∆ ⊢ e ⇝c v and ∆′ = ∆[x ← v], while H ′ = H, η ′ = ηs , ν ′ = ν, and µ′ = µ. Applying sub-assign, we obtain ∆s , I ⊢ x := e −→sub x := e1 with ∆s , I ⊢ e 7→sub e1 . Now, let us assume that we have ∆′′ such that it satisfies the symbolic state, i.e., (∆′′ ) |= (∆s , π), and ∆ ⊆ ∆′′ . By the lemma on expression substitution (Lemma 11.1), ∆′′ ⊢ e1 ⇝c v. Now, concretely executing the rewritten statement in ∆′′ , we get Θ ⊢ ((η, ∆′′ , H, ν, µ), x := e1 ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ), which must be of the form η ′′′ = η = η ′ , H ′′′ = H = H ′ , ν ′′′ = ν = ν ′ , and µ′′′ = µ = µ′ (conclusion 1). Note that, we also have that we assumed ∆ ⊆ ∆′′ , and that the only change introduced in the mapping for x, i.e., ∆′ = ∆[x ← v], ∆′′′ = ∆′′ [x ← v]. By transitivity, we can conclude that ∆′ ⊆ ∆′′′ (conclusion 2). Finally, since ∀i ∈ I.¬isU se(i, e1 ) by the

36

expression lemma and x cannot be not an input, since x ∈ / getInput(x := e) while I only contains variables i such that isU se(i, s) ∧ ¬isDef (i, s), we conclude ∀i ∈ I.¬isU se(i, x := e1 ) (conclusion 3). Next, consider the sub-comp rule. There are two cases that can occur when evaluating a compositional statement in the concrete semantics: either s1 has a return control flow (thus the composition-ret rule will apply), or not (thus the composition rule will apply). Since, the substitution transformation happens after the remove final return transformation (Property A.16), thus we will skip the case where a return can happen in s1 . Thus, to show that the lemma holds for the composition rule, we have Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ) and Θ ⊢ ((η1 , ∆1 , H1 , ν1 , µ), s2 ) ⇒c (η2 , ∆2 , H2 , ν2 , µ). Here we have that η ′ = η2 , ∆′ = ∆2 , H ′ = H2 , ν ′ = ν2 , µ′ = µ. Now, applying the rewriting, we get ∆s , I ⊢ s1 ; s2 −→sub s′1 ; s′2 . Now, let us assume we have ∆′′ such that it satisfies the symbolic state, i.e., (∆′′ ) |= (∆s , π), and where ∆ ⊆ ∆′′ . Using induction hypothesis on s1 , we have that Θ ⊢ ((η, ∆′′ , H, ν, µ), s′1 ) ⇒c (η1 , ∆3 , H1 , ν1 , µ), such that ∆1 ⊆ ∆3 . From Lemma 4.2, we know that ∆′′ ⊆ ∆1 , since we have established that (∆′′ ) |= (∆s , π), then by transitivity, it must be that (∆3 ) |= (∆s , π), and similarly, (∆′′ ) |= (∆s , π) Now, we can use this state and apply induction on s2 to get Θ ⊢ ((η1 , ∆3 , H1 , ν1 , µ), s′2 ) ⇒c (η2 , ∆4 , H2 , ν2 , µ), such that ∆2 ⊆ ∆4 . Here, we have that η ′′′ = η2 = η ′ , H ′′′ = H2 = H ′ , ν ′′′ = ν2 = ν ′ , µ′′′ = µ2 = ⊥ = µ′ (conclusion 1). Also, we have that ∆′′′ = ∆4 , and ∆′ = ∆2 , and we have shown that ∆2 (x) ⊆ ∆4 (x) (conclusion 2). Finally, to prove ∀i ∈ I. ¬isU se(i, s′1 ; s′2 ), we apply induction on both s1 and s2 . From the induction hypothesis, ∀i ∈ I. ¬isU se(i, s′1 ) and ∀i ∈ I. ¬isU se(i, s′2 ). By the definition of isU se, a variable is used in a composition only if it is used in one of the components. Hence, ∀i ∈ I. ¬isU se(i, s′1 ; s′2 ) (conclusion 3). Consider the sub-getfield rule, we have that Θ ⊢ ((η, ∆, H, ν, ⊥), get f ield(x, z, f )) ⇒c (η, ∆[x ← v], H, ν, ⊥), where r ∈ R, r = ∆(z), and v = H(r, f ), by applying the get-field rule. Here we have that η ′ = ηs , ∆′ = ∆[x ← v], H ′ = H, ν ′ = ν, µ′ = ⊥. On the other hand, we can apply the sub-getfield rule to get ∆s , I ⊢ get f ield(x, z, f ) −→sub get f ield(x, z ′ , f ), for some reference variable z and a field f . Now, let us assume we have ∆′′ such that it satisfies the symbolic state, i.e., (∆′′ ) |= (∆s , π), where ∆ ⊆ ∆′′ . Using the substitution lemma for expression soundness (Lemma 11.1), we have ∆′′ ⊢ z ′ ⇝c r. Thus, evaluating concretely the rewritten statement we get, Θ ⊢ ((η, ∆′′ , H, µ), get f ield(x, z ′ , f )) ⇒c (η, ∆′′ [x ← v ′ ], H, ⊥). Here, we have that η ′′′ = η = η ′ , H ′′′ = H = H ′ , ν ′′′ = ν = ν ′ , µ′′′ = µ = ⊥ = µ′ (conclusion 1). Next, we have that ∆′′′ = ∆′′ [x ← v ′ ], v ′ = H(r, f ) = v. From the SSA guarantees from previous transformation, we know that SS(s) most hold (Property A.1), x cannot appear in ∆ or ∆′′ , nor can x ∈ I since isDef (x, get f ield(x, z ′ , f )) holds while I only contains variables i such that isU se(i, s) ∧ ¬isDef (i, s). As [x ← v] is the only update in both ∆′ and ∆′′′ , pairing that with the assumed fact that ∆ ⊆ ∆′′ , then we can conclude that ∆′ ⊆ ∆′′′ (conclusion 2). Finally, to show that ∀i ∈ I.¬isU se(i, s′ ), observe that we have ∀i ∈ I.¬isU se(i, z ′ ) from the expression lemma, then it must be the case that ∀i ∈ I.¬isU se(i, get f ield(x, z ′ , f )) (conclusion 3). Consider the sub-putfield rule, we apply the put-field rule Θ ⊢ ((η, ∆, H, ν, ⊥), put f ield(z, f, e)) ⇒c (ηs , ∆, H[(r, f ) ← v], ν, ⊥), such that r = ∆(z), r ∈ R, and ∆ ⊢ e ⇝c v. Here we have that η ′ = ηs , ∆′ = ∆, H ′ = H[(r, f ) ← v], ν ′ = ν, µ′ = ⊥. On the other hand, we can apply the sub-putfield rule to get ∆s , I ⊢ put f ield(z, f, e) −→sub put f ield(z ′ , f, e′ ) , such that ∆s , I ⊢ e 7→sub e′ , ∆s , I ⊢ z 7→sub z ′ . Now, let us assume we have ∆′′ such that it satisfies the symbolic state, i.e., (∆′′ ) |= (∆s , π), where ∆ ⊆ ∆′′ . First, observe that both z ′ and e′ will evaluate to the same value as their non-rewritten counter parts, due to Lemma 11.1, i.e,

37

∆′′ ⊢ e′ ⇝c v, and ∆′′ ⊢ z ′ ⇝c r Now, evaluating the rewritten statement we get, Θ ⊢ ((η, ∆′′ , H, ν, ⊥), put f ield(z ′ , f, e′ )) ⇒c (η ′′′ , ∆′′′ , H ′′ , ν ′′′ , µ′′′ ). Note here we get the same heap, that is, H ′′ = H[(r, f ) ← v] = H ′ . Also, observe that no other environment variables are changed, thus we can arrive to conclusion 1. Next, observe that no change has occurred on the local variable mapping, i.e., ∆′′′ = ∆′′ , and that ∆′ = ∆ pairing that with the assumed fact that ∆ ⊆ ∆′′ , then we can conclude that ∆′ ⊆ ∆′′′ (conclusion 2). Finally, one of the conclusions of applying the expression lemma on both z, and e, is that that ∀i ∈ I.¬isU se(i, z ′ ), and ∀i ∈ I.¬isU se(i, e′ ), thus we can conclude that ∀i ∈ I.¬isU se(i, put f ield(z ′ , f, e′ )), since the putfield construct does not introduce additional variables (other than those in z ′ and in e′ ) to the rewritten statement (conclusion 3). Now, consider the sub-invoke rule, we have that Θ ⊢ → ((η, ∆, H, ν, µ), invoke(x, z, g, − y )) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ), such that µ = ⊥, → → → ∆ ⊢ z ⇝c r, r ∈ R, Θ(η(r), g) = method(− y1 .s1 ), ∆ ⊢ − y ⇝c − v1 , and − → − → 5 5 5 5 5 Θ ⊢ ((η, {(y1 , v1 )}, H, ν, ⊥), s1 ) ⇒c (η , ∆ , H , ν , µ ). Here, we have that η ′ = η 5 , ∆′ = ∆[x ← − µ5 ], H ′ = H 5 , ν ′ = ν 5 =, and µ5 = v ′ , v ′ ̸= ⊥. Next, we can apply the − → → sub-invoke to get ∆s , I ⊢ invoke(x, z, g, − y ) −→sub invoke(x, z ′ , g, y ′ ) and we have − → → ∆s , I ⊢ − y 7→sub y ′ , and ∆s , I ⊢ z 7→sub z ′ . Now, let us assume we have ∆′′ such that it satisfies the symbolic state, i.e., (∆′′ ) |= (∆s , π), where ∆ ⊆ ∆′′ . First, observe that both z ′ and y ′ will evaluate to the same − → → value as their non-rewritten counter parts, due to Lemma 11.1, i.e, ∆′′ ⊢ y ′ ⇝ − v , and c

1

∆′′ ⊢ z ′ ⇝c r. This implies that the fetched method for invocation must also match the one → that is fetched when evaluating the original statement, that is Θ(η(r), g) = method(− y1 .s1 ). Now, we can evaluate s1 in exactly the same way in the original statement, to get Θ ⊢ → → ((η, {(− y1 , − v1 )}, H, ν, ⊥), s1 ) ⇒c (η 6 , ∆6 , H 6 , ν 6 , µ6 ). But since we are evaluating s1 in exactly the same environment then it must be the case that η 6 = η 5 , ∆6 = ∆5 , H 6 = H 5 , ν 6 = ν 5 , µ6 = µ5 . Moreover, we can also conclude that the resulting concrete state (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ) must be of the form η ′′′ = η 6 = η 5 = η ′ , H ′′′ = H 6 = H 5 = H ′ , ν ′′′ = ν 6 = ν 5 = ν ′ , and finally, µ′′′ = µ6 = µ5 = ⊥ (conclusion 1). Next, observe that ∆′′′ = ∆′′ [x ← µ5 ], and similarly we have that ∆′ = ∆[x ← µ5 ], and since we have established that ∆ ⊆ ∆′′ , thus adding the single mapping for x, must still maintain the subset relationship, i.e., ∆′ ⊆ ∆′′′ (conclusion 2). − → Finally, it is easy to see that ∀i ∈ I.¬isU se(i, invoke(z ′ , x, g, y ′ )) by using the expression − → → lemma on both z and − y , we obtain that ∀i ∈ I.¬isU se(i, z ′ ), and ∀i ∈ I.¬isU se(i, y ′ ), − → thus we can conclude that ∀i ∈ I.¬isU se(i, invoke(z ′ , x, g, y ′ )), since the invoke construct − → does not introduce additional variables (other than those in z ′ and in y ′ ) to the rewritten statement (conclusion 3). Finally, consider the sub-if rule. The proof splits into several cases depending on whether the if-condition evaluates to true or false, and whether the executed branch contains a return. We present the proof for two representative cases: when the condition evaluates to true and the taken branch s1 has no return, and when the condition still evaluates to true but s1 contains a return, noting that the latter is skipped due to SSA guarantees from pervious transformations (Property A.1). Recall that this transformation is applied after the γ-transformation, which eliminates ϕ-statements from if-statements; therefore, we assume the sequence of ϕ-statements is empty. First, let us consider the first case. Here we have that Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ), where ∆ ⊢ e ⇝c true, Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ), and µ′ = ⊥ = µ. Applying the sub-if rule we get ∆s , I ⊢ if e then s1 else s2 −→sub if e′ then s′1 else s′2 , such that we have

38

∆s , I ⊢ e 7→sub e′ , and also ∆s , I ⊢ s1 −→sub s′1 , and finally, ∆s , I ⊢ s2 −→sub s′2 . First, observe that and e′ must evaluate to the same value as its non-rewritten counter parts, due to Lemma 11.1, i.e, ∆′′ ⊢ e′ ⇝c true. Thus, the concrete evaluation will evaluate the then-side (s1 ). Here, we use induction over s1 . That is, if we have that Θ ⊢ ((η, ∆′′ , H, ν, ⊥), s′1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ), then by induction, we know that η1 = η ′ , H1 = H ′ , ν1 = ν ′ , µ1 = ⊥, and ∆1 = ∆′′′ (conclusion 1). Similarly by induction we have that ∆′ ⊆ ∆′′′ (conclusion 2). Finally, to show that ∀i ∈ I.¬isU se(i, s′ ), observe that we have ∀i ∈ I.¬isU se(i, e′ ) holds by using the expression lemma, also, by using induction over s1 , and s2 , we have that ∀i ∈ I.¬isU se(i, s′1 ) ∧ ¬isU se(i, s′2 ). then it must be the case that ∀i ∈ I.¬isU se(i, if e′ then s′1 else s′2 ) (conclusion 3). □

Corollary 11.3 (The substitution-wrapper is sound). If Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) ∆s ⊢ ((πr , µs , I ), s) −→sub−wrap ((πr′ , µ′s , I ′ ), s′ )

∀i ∈ I.∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) µ∗ = evalReturn(∆′ , πr , µs ) ′′ then for any ∆ such that (∆′′ ) |= (∆s , π ) ∆ ⊆ ∆′′ Θ ⊢ ((η, ∆′′ , H, ν, µ), s′ ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ )

we have η ′′′ = η ′ , H ′′′ = H ′ , ν ′′′ = ν ′ , µ′′′ = µ′ ∆′ ⊆ ∆′′′ ∀i ∈ I.¬isU se(i, s′ ) (∆′′′ ) |= (∆s , π ′ ) ∗ µ = evalReturn(∆′′′ , πr′ , µ′s ) Proof Applying sub-wrap rule on a statement s, we get ∆s ⊢ ((πr , µs , I), s) −→sub−wrap ((πr′ , µ′s , I ′ ), s′ ), such that ∆s , I ⊢ s −→sub s′ , ∆s , I ⊢ πr 7→sub πr′ , ∆s , I ⊢ µs 7→sub µ′s , and I ′ = getInput(s′ ) ∪ getU se(µ′s ) ∪ getU se(πr′ ). Given the premise of the corollary we can apply the of Theorem 11.2 on s′ to show conclusion 1-4: Θ ⊢ ((η, ∆′′ , H, ν, µ), s′ ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ) η ′′′ = η ′ , H ′′′ = H ′ , ν ′′′ = ν ′ , µ′′′ = µ′ ∆′ ⊆ ∆′′′ ∀i ∈ I.¬isU se(i, s′ ) Next, we want to show that (∆′′ ) |= (∆s , π). Since the evaluation of this relation depends on its arguments. From Lemma 4.2, we know that ∆′′ ⊆ ∆′′′ , then π will be evaluated exactly the same in ∆′′ , which in turn guarantees that (∆′′′ ) |= (∆s , π) must also hold. Finally, from the premise of the corollary, we have µ∗ = evalReturn(∆′ , πr , µs ). The evaluation of evalReturn depends on the evaluation of the expressions πr and µs under ∆.

39

Since we have shown that ∆′ ⊆ ∆′′′ and πr′ , µ′s are the rewritten counterparts of πr , µs , respectively, Lemma 11.1 applies. Therefore, evalReturn(∆′′′ , πr′ , µ′s ) = evalReturn(∆′ , πr , µs ) = µ∗ . □

Let ∆∗ be the restriction of ∆′′ to variables not in I , i.e.,

Dom(∆∗ ) = Dom(∆′′ ) \ I Corollary 11.4 (Substitution-wrapper is sound even if we remove input variables). Assume the premises of Corollary 11.3. Let ∆∗ be defined as above, we observe that ∆∗ ⊂ ∆′′ . Then, we know that if Θ ⊢ ((η, ∆∗ , H, ν, µ), s′ ) ⇒c (η 4 , ∆∗∗ , H 4 , ν 4 , µ4 )

then the following hold: η4 = η′ ,

H 4 = H ′,

ν4 = ν′,

µ4 = µ′

∀x. ∈ Dom(∆s ).(∆∗ , ∆s (x)) ⇝c ∆′′ (x) ∆∗∗ ⊂ ∆′′′ ∗ µ = evalReturn(∆∗∗ , πr′ , µ′s ) (∆∗∗ ) |= (∆s , π ) Proof By Corollary 11.3, we have ∀i ∈ I.¬isU se(i, s′ ). Since ∆∗ differs from ∆′′ only on variables in I, the execution of s′ under ∆∗ yields η 4 = η ′′′ = η ′ , H 4 = H ′′′ = H ′ , ν 4 = ν ′′′ = ν ′ , µ4 = µ′′′ = µ′ (conclusion 1). Also, observe that since we have established that (∆′′′ ) |= (∆s , π), and that we also know from the premise of Corollary 11.3 that ∀i ∈ I.∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)). Then this implies that the evaluation of any variable x in Dom(∆s ) is not dependent on the input variable mapping, and since the only difference between ∆∗ and ∆′′ is the input variable mappings, then we can conclude that ∀x. ∈ Dom(∆s ).(∆∗ , ∆s (x)) ⇝c ∆′′ (x) (conclusion 2). We want to know that the subset relation will be preserved with the execution of s′ , and this follows because the execution of s′ initially starts with the assumption that both ∆∗ and ∆′′ match up on all variable excluding those in I. Thus, expressions, as they are not using any variables from I, must evaluate to the same values in both environments. Moreover, all state updates must also make the same updates, thus preserving the subset relation between resulting states, i.e., ∆∗∗ ⊂ ∆′′′ . Also, by Lemma 11.1, input variables do not occur in πr′ or µ′s , and since we have from Corollary 11.3 that, µ∗ = evalReturn(∆′′′ , πr′ , µ′s ), then we can conclude that evaluating πr′ and µ′s under ∆∗∗ , and is unchanged. Therefore, µ∗ = evalReturn(∆∗∗ , πr′ , µ′s ). Finally, by Lemma 11.1, input variables do not occur in πr′ and that it evaluates to the same value in ∆′′′ according to the same lemma. We also have established that ∀x. ∈ Dom(∆s ).(∆∗ , ∆s (x)) ⇝c ∆′′ (x), then that means that it must evaluate to the same value in ∆ ∗ ∗. Same reasoning applies for all expressions mapped to by any variable x such that s ∈ Dom(∆s ), this implies that the evaluation for (∆∗∗ ) |= (∆s , π) must hold. □

40

11.1 Substitution Properties The substitution assumes all guaranteed properties from γ -creation, remove finalreturns and renaming transformations. And it guarantees the following properties. Given ∆s ⊢ ((πr , µs , I ), s) −→sub−wrap ((πr′ , µ′s , I ′ ), s′ ), such that ∆s , I ⊢ s −→sub s′ and ∆s , I ⊢ πr 7→sub πr′ , ∆s , I ⊢ π 7→sub π ′ where ∆s , I ⊢ µs 7→sub µ′s and I ′ = getInput(s′ ) ∪getU se(µ′s ) ∪getU se(πr′ ), then the substitution transformation has the following guarantees.

• Rewritten Statement s′ satisfies the generalized SSA property. More formally, SSA(s′ ) holds. Proof This follows directly, from renaming transformation guarantee (Property A.1) that the SSA(s) holds and that none of the expression rules (7→sub ) alter the local variable mapping or the heap mappings. Likewise, none of the statement rules (→sub ) modify the variables assigned within generalized assignment statements, nor do they introduce new variables. Consequently, because neither variable mappings nor assignments are changed, the generalized SSA property is preserved for s′ , i.e., SSA(s′ ) holds. □

• No input variables i ∈ I exist in the rewritten statement s′ . More formally, ∀x ∈ I, ¬isU se(x, s′ ) Proof This follows directly from applying the soundness theorem 11.4 of the substitution transformation. □

12 T R6 : Method Inlining Transformation This transformation inlines the IR of called methods one level at a time. Inlining is performed only when the object reference on which the method is invoked is a concrete reference. Fig. 13 shows a snippet of the main rules for this transformation. The rules define two judgments. The judgment Θt , ηs , ∆s ⊢ ((T, u), s) −→inline ((T ′ , u′ ), s′ ) rewrites an IR statement s into s′ by inlining method calls, where Θt is the mapping of transformed method bodies, ηs is the reference-to-type mapping, ∆s is the symbolic local variable mapping, T is the set of temporary variables, and u is the global unique index. Their primed counterparts T ′ and u′ reflect their updated values after rewriting. The wrapper judgment Θt , ηs , ∆s ⊢ ((T, u), s) −→inline-wrap ((T ′ , u′ ), s′ ) is the entry point of the transformation, triggering the inline judgment on s. Rule inline-invoke inlines a method call by looking up its transformed body in Θt , which contains the IR of methods on which the γ -transformation, early-return elimination, and final-return removal have already been applied (see Appendix B). The rule retrieves the transformed body, applies the renaming transformation to ensure uniqueness of variable names, and applies substitution to propagate the passed arguments into the body. The variable x is then assigned the modified return expression µ3s of the inlined method. Rules inline-comp propagates the transformation into their sub-statements, threading the temporary variable set T and counter u through each; the rule for conditionals, omitted from Fig. 13 for brevity, follows the same pattern.

41

All remaining statement forms, including assignments, getfield, and putfield, etc., are handled by Rule inline-no-op, which leaves them unchanged. ′

′

′

Θt , ηs , ∆s ⊢ ((T, u), s) −→inline ((T , u ), s ) Θt , ηs , ∆s ⊢ ((T, u), s) −→inline−wrap ((T ′ , u′ ), s′ ) ′

′

′

′

Θt , ηs , ∆s ⊢ ((T, u), s1 ) −→inline ((T , u ), s1 )

inline−wrap

′

′′

′′

′

Θt , ηs , ∆s ⊢ ((T , u ), s2 ) −→inline ((T , u ), s2 ) inline−if

Θt , ηs , ∆s ⊢ ((T, u), if e then s1 else s2 ) −→inline ((T ′′ , u′′ ), if e then s′1 else s′2 )

r∈R

→ −′ ′ ′ ′ ((µs , πr ), y .s ) = Θt (ηs (r), g) ′

′

′

′

′

′

O =∅

′

→ −′ ′ I =y ′′

′

′

T = getOutput(s )

′′

′′

′

′′

I , O ⊢ ((µs , πr , T , u), s ) −→rename−wrap ((µs , πr , T , u ), s ) → −′ σ = (I , y ) ′

′′ ′′ ′ ′′ σ ⊢ ((true, πr , µs , I ), s )

3 3 ′′ 3 −→sub−wrap ((true, πr , µs , I ), s )

T

3

=T

′′

∪T inline−invoke

− Θt , ηs , ∆s ⊢ ((T, u), invoke(x, r, g, → y )) −→inline ((T 3 , u′ ), s3 ; x := µ3s ) ′

′

′

Θt , ηs , ∆s , ⊢ ((T, u), s1 ) −→inline ((T , u ), s1 )

′

′

′′

′′

′

Θt , ηs , ∆s ⊢ ((T , u ), s2 ) −→inline ((T , u ), s2 ) ′′

Θt , ηs , ∆s ⊢ ((T, u), s1 ; s2 ) −→inline ((T , u noOpinline (s) Θt , ηs , ∆s ⊢ ((T, u), s) −→inline ((T, u), s)

′′

), s′1 ; s′2 )

inline−comp

inline−no−op

Figure 13: Method-Inlining Rules

Here the noOpinline (s) is defined as

noOpinline (x := e) = true noOpinline (get f ield(x, z, f )) = true noOpinline (put f ield(z, f, e)) = true noOpinline (skip) = true noOpinline (new(x, c)) = true noOpinline (s) = f alse otherwise

12.1 Method-Inlining Transformation is Sound Lemma 12.1 (transform + rename + substitution). Given a parametric statement → − y .s, we have ((µ′s , πr′ ), s′ ) = transf orm(s) Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) − − − O′ = ∅, T = getOutput(s′ ), I ′ = → y , ∆′s = (→ y ,→ x) ′ ′ ′ ′ ′ ′′ ′′ ′ I , O ⊢ ((πr , µs , T, u), s ) −→rename−wrap ((µs , πr , T , u′ ), s′′ ) − I′ ∩ → x =∅ ∗ then for any ∆ such that

42

(∆∗ ) |= (∆′s , π ) ∆ ⊆ ∆∗ ∆′s ⊢ ((πr′′ , µ′′s , I ′ ), s′′ ) −→sub−wrap ((πr3 , µ3s , I ′′ ), s3 ) Θ ⊢ ((η, ∆∗ , H, ν, µ), s3 ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ )

then η ′ = η ′′ , H ′ = H ′′ , ν ′ = ν ′′ , µ′′ = µ′ µ′ = evalReturn(∆′′ , πr3 , µ3s ) (∆′′ ) |= (∆s , π ) Proof We structure the proof in three stages. First, we characterize the intermediate state produced by applying the transform function. Next, we analyze the state resulting from the rename-wrap judgment. Finally, we apply the sub-wrap judgment, yielding a state that matches the lemma’s conclusion. First, we apply Lemma B.1, such that Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν, µ′ ) ((µ′s , πr′ ), s′ ) = transf orm(s) then, we get

Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 ) η ′ = η 4 , ∆′ = ∆ 4 , H ′ = H 4 , ν ′ = ν 4 µ′ = evalReturn(∆4 , πr′ , µ′s ), µ4 = ⊥

Next, since we have that Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 ) µ4 = ⊥ ′

I ,O

′

⊢ ((πr′ , µ′s , T, u), s′ )

′′ ′ ′ ′′ −→rename−wrap (µ′′ s , πr , T , u ), s )

then, we can apply renaming Theorem (Theorem 10.3) to get Θ ⊢ ((η, ∆, H, ν, µ), s′′ ) ⇒c (η 5 , ∆5 , H 5 , ν 5 , µ5 ) evalReturn(∆4 , πr′ , µ′s ) = evalReturn(∆5 , πr′′ , µ′′ s) where η 5 = η 4 = η ′ , H 5 = H 4 = H ′ , ν 5 = ν 4 = ν ′ = ⊥, µ5 = µ4 = ⊥. Also, observe that we have established from before that µ′ = evalReturn(∆4 , πr′ , µ′s ), and we also have shown that evalReturn(∆4 , πr′ , µ′s ) = evalReturn(∆5 , πr′′ , µ′′ s ), thus by transitivity, we have µ′ = evalReturn(∆5 , πr′′ , µ′′ s) Next, consider the sub-wrap. From the premise of the theorem we have that ∆∗ be a concrete state such that (∆∗ ) |= (∆′s , π) where ∆ ⊆ ∆∗ , and µ5 = ⊥. Also, observe that → → from the statement theorem we know that ∆′s is constructed as ∆′s = (− y ,− x ), such that − → − → ′ ′ ′ I ∩ x = ∅, and since I = y , thus if follows that ∀i ∈ I .∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)). With all the above observations, we can now use the substitution (Corollary 11.3), such that we have ′ ′′ 3 3 ′′ 3 ∆′s ⊢ ((πr′′ , µ′′ s , I ), s ) −→sub−wrap ((πr , µs , I ), s )

we get

43

Θ ⊢ ((η, ∆∗ , H, ν, µ), s3 ) ⇒c (η 6 , ∆6 , H 6 , ν 6 , µ6 ) η 6 = η ′′ = η 5 , H 6 = H ′′ = H 5 , ν 6 = ν ′′ = ν 5 , µ6 = µ′′ = µ5 ∆5 ⊆ ∆ 6 ∀i ∈ I ′ .¬isU se(i, s3 ) (∆6 ) |= (∆s , π) 6 3 3 evalReturn(∆5 , πr′′ , µ′′ s ) = evalReturn(∆ , πr , µs ) ′′ 6 5 Observe here that by transitivity we get, η = η = η = η 4 = η ′ , H ′′ = H 6 = H 5 = 4 H = H ′ , ν ′′ = ν 6 = ν 5 = ν 4 = ν ′ , µ′′ = µ6 = µ5 = µ4 = ⊥ (conclusion 1). And we already established (∆6 ) |= (∆s , π) (conclusion 2) Finally, it follows directly from applying Corollary 11.3, i.e., evalReturn(∆5 , πr′′ , µ′′ s) = evalReturn(∆6 , πr3 , µ3s ), since we have that ∆′′ = ∆6 , then by transitivity we have 4 ′ ′ ′ evalReturn(∆6 , πr3 , µ3s ) = evalReturn(∆5 , πr′′ , µ′′ s ) = evalReturn(∆ , πr , µs ) = µ (conclusion 3). □

Lemma 12.2 (transform + rename + substitution - no input). Assume the premises of Corollary 12.1, where an additional local variable mapping ∆∗∗ is defined as Dom(∆∗∗ ) = Dom(∆∗ ) \ I and ∆∗∗ ⊂ ∆∗ Θ ⊢ ((η, ∆∗∗ , H, ν, µ), s3 ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ) then η ′′′ = η ′′ = η ′ , H ′′′ = H ′′ = H ′ , ν ′′′ = ν ′′ = ν ′ , µ′′′ = µ′′ = µ′ ∆′′′ ⊂ ∆′′ ′ µ = evalReturn(∆′′′ , πr3 , µ3s ) (∆′′′ ) |= (∆s , π ) Proof The proof directly follow from applying Corollary 11.4.

□

Theorem 12.3 (Inlining recursive judgment is sound). If Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) Θt , ηs , ∆s ⊢ ((T, u), s) −→inline ((T ′ , u′ ), s′ ) ηs ⊆ η (∆) |= (∆s , π ) Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ )

then ∆′ ⊆ ∆′′

(1)

η = η , H = H ′ , ν ′′ = ν ′ , µ′′ = µ′ ηs ⊆ η ′′ (∆′′ ) |= (∆s , π )

(2)

′

′′

′′

44

(3) (4)

Proof We proceed by induction on the inlining rules. First, consider the case inline-no-op, and inline-invoke-stop rules. Since inlining introduces no changes to the statements or environments in either case, then, we have Θt , ηs , ∆s ⊢ ((T, u), s) −→inline ((T, u), s)

where noOpinline (s) holds,

′

and therefore s = s. Executing s gives the concrete step Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ), and since s = s′ , we obtain η ′ = η ′′ , H ′ = H ′′ , and ν ′ = ν ′′ . Furthermore, because noOpinline (s) holds, s contains no return statement (plus the guarantee from the remove final-returns (Property A.16), and thus µ′ = ⊥ = µ (conclusion 2). Since we have that ∆′′ = ∆′ , it follows that ∆′ ⊆ ∆′′ (conclusion 1). Also, we have established that η ⊆ η ′′ , and since ηs ⊆ η (from the hypothesis), then by transitivity, we conclude that the ηs ⊆ η ′′ (conclusion 3). Finally, we have (∆) |= (∆s , π) from the premise, and we know from Lemma 6.1 that ∆ ⊆ ∆′ . Also, we have just shown that ∆′ ⊆ ∆′′ , then that means that evaluating π and all expressions mapped to within ∆s results in the same values, thus we can conclude that (∆′′ ) |= (∆s , π). Now, consider the inline-if rule. Here we have that Θt , ηs , ∆s ⊢ ((T, u), if e then s1 else s2 ) −→inline ((T2 , u2 ), if e then s′1 else s′2 ) such that Θt , ηs , ∆s ⊢ ((T, u), s1 ) −→inline ((T1 , u1 ), s′1 ), and Θt , ηs , ∆s ⊢ ′ ((T1 , u1 ), s2 ) −→inline ((T2 , u2 ), s2 ). On the other hand, using the concrete semantics either the if-phi-true or if-phi-false can only apply depending on the evaluation of e. We will show the proof for the if-phi-true case, but the proof for the if-phi-false case works similarly. Note that, no return statement can exist in s due to the guarantee from the remove final-returns transformation (Property A.16) thus other rules for concretely executing an if-statement can be ignored. First, consider the if-phi-true case. Then we have that ∆ ⊢ e ⇝c true and ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ). Observe here that, η1 = η ′ , ∆1 = η ′ , H1 = H ′ , ν1 = ν ′ , µ1 = µ′ . Applying the induction hypothesis to s1 , we have that ((η, ∆, H, ν, µ), s′1 ) ⇒c (η1′ , ∆′1 , H1′ , ν1′ , µ′1 ) where η1′ = η1 , H1′ = H1 , ν1′ = ν1 , µ′1 = ⊥ (conclusion 2), ∆1 ⊆ ∆′1 (conclusion 1) and ηs ⊆ η1′ (conclusion 3). Also, observe here that η1′ = η ′′ , ∆′1 = ∆′′ , H1′ = H ′′ , ν1′ = ν ′′ , µ′1 = µ′′ . Thus, by transitivity we have our conclusions satisfied. Finally, we have (∆) |= (∆s , π) from the premise, and we know from Lemma 6.1 that ∆ ⊆ ∆1 . Also, we have just shown that ∆1 ⊆ ∆′1 , then that means that evaluating π and all expressions mapped to within ∆s results in the same values using ∆′1 , thus we can conclude that (∆′1 ) |= (∆s , π) (conclusion 4). Next, consider the inline-comp rule. In this case we have Θt , ηs , ∆s ⊢ ((T, u), s1 ; s2 ) −→inline ((T ′′ , u′′ ), s′1 ; s′2 ) where Θt , ηs , ∆s , ⊢ ((T, u), s1 ) −→inline ((T ′ , u′ ), s′1 ), and Θt , ηs , ∆s ⊢ ′ ′′ ′′ ′ ((T , u ), s2 ) −→inline ((T , u ), s2 ). Again, due to the guarantee from the remove final-returns transformation (Property A.16), we know that s1 ; s2 cannot contain return-statements, and none of the inlining rules generate a return-statement, so a return-statement cannot be in s′1 , nor s′2 . Then, then the only concrete rule that applies is the composition rule. Thus, we have that Θ ⊢ ((η, ∆, H, ν, µ), s1 ; s2 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) such that Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ) and Θ ⊢ ((η1 , ∆1 , H1 , ν1 , µ), s2 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ). By applying the induction hypothesis on ′

45

s1 we get Θ ⊢ ((η, ∆, H, ν, µ), s′1 ) ⇒c (η1′ , ∆′1 , H1′ , ν1′ , µ′1 ), such that η1′ = η1 , H1′ = H1 , ν1′ = ν1 , µ′1 = ⊥, ∆1 ⊆ ∆′1 and ηs ⊆ η1′ . Now, executing s′2 in the resulting state we get Θ ⊢ ((η1′ , ∆′1 , H1′ , ν1′ , µ′1 ), s′2 ) ⇒c (η2 , ∆2 , H2 , ν2 , µ2 ). By applying the induction hypothesis on s2 , we get η2 = η ′ , H2 = H ′ , ν2 = ν ′ , µ2 = ⊥, ∆′ ⊆ ∆2 and ηs ⊆ η2 . Here we have that ∆2 = ∆′′ , H2 = H ′′ , ν2 = ν ′′ , µ2 = µ′′ , we get by transitivity η ′′ = η2 = η ′ , H ′′ = H2 = H ′ , ν ′′ = ν2 = ν ′ , µ′′ = µ2 = ⊥ (conclusion 3), ∆′ ⊆ ∆′′ (conclusion 1) and ηs ⊆ η2 = η ′′ (conclusion 3). Finally, we have (∆) |= (∆s , π) from the premise, and we know from Lemma 6.1 that ∆ ⊆ ∆′1 ⊆ ∆′ . Also, we have just shown that ∆′ ⊆ ∆′′ , then that means that evaluating π and all expressions mapped to within ∆s using ∆′ , must reduce to the same values, thus we can conclude that (∆′′ ) |= (∆s , π) (conclusion 4). Finally, consider the inline-invoke rule. In this case we have that →)) −→ Θ , η , ∆ ⊢ ((T, u), invoke(x , r, g, − x ((T , u ), s3 ; x := µ3 ) t

s

s

1

2

inline

3

1

1

s

such that r∈R → ((µ′s , πr′ ), − y .s1 ) = Θt (ηs (r), g) ′ ′ → O =∅ I =− y T1 = getOutput(s1 ) ′ ′ ′ ′ ′′ ′ ′ I , O ⊢ ((µs , πr , T1 , u), s1 ) −→rename−wrap ((µ′′ s , πr , T1 , u ), s2 ) → →) ∆′s = (− y ,− x 2 ′ ′′ ′′ ′ ∆s ⊢ ((µs , πr , I ), s2 ) −→sub−wrap ((µ3s , πr3 , I ′′ ), s3 ) T1′′ = T1′ ∪ T In this case, we have that s′ = s3 ; x1 := µ3s , T ′ = T1′′ . Executing the original statement concretely, we get →)) ⇒ (η ′ , ∆′ , H ′ , ν ′ , µ′ ) Θ ⊢ ((η, ∆, H, ν, µ), invoke(x1 , r, g, − x c 2 such that r∈R

− → Θ(η(r), g) = y ′ .s′1 − → → ∆⊢− e ⇝c v ′ − → − → ∆t = {( y ′ , v ′ )} Θ ⊢ ((η, ∆t , H, ν, µ), s′1 ) ⇒c (η ′ , ∆′t , H ′ , ν ′ , µ′ ) ∆′ = ∆[x1 ← − µ′ ] µ′ ̸= ⊥ Since we have that ηs ⊆ η, then we know that η(r) = ηs (r) = c, for a class c. − → Now, recall that Θ(c, g) = y ′ .s′1 , while the Θt , according to its definition, is the transformed version of each class-method pair, if ((µ′s , πr′ ), s1 ) = transf orm(s′1 ) − → → → then ((µ′s , πr′ ), − y .s1 ) ∈ Θt according to these definitions, we shown that y ′ = − y Next, observe that the premise of the inline-invoke rule is already matching up with the → premise of Lemma 12.1, more importantly that we have, O′ = ∅, I ′ = − y , T1 = getOutput(s1 ) − → − → ′ and that ∆s = ( y , x2 ). → = ∅. Once again, referring to the remove final-returns It remains to show that I ′ ∩ − x 2 → must transformation guaranteed property (Property A.16), we know that all variables in − x 2

46

have been renamed as part of renaming of the statement containing s. On the other hand, → we know that − y , must not have been renamed before. More precisely, for all variables y in − → →, must be of the form (a, n), y , y must be of the form (a, ⊥), whereas all variables x in − x 2 where n is a constant int. Because of mismatched suffixes within the variable names, we can → = ∅. conclude that I ′ ∩ − x 2 Also, observe that (∆) |= (∆s , π) by the premise of the Theorem. Now let us choose ∆∗ = ∆ ∪ ∆t . Here, we can also see that (∆∗ ) |= (∆′s , π), this is because, we know that → →), and since we have that (∆) |= (∆ , π), which means ∆′s is constructed as ∆′s = (− y ,− x s 2 → must evaluate in ∆ must yield (∆, − →) ⇝ − → that evaluating expressions in − x x c v , such that 2 2 → − → ∗ − ∗ ′ ∆ ( y ) = v , thus we can conclude that (∆ ) |= (∆s , π). And obviously we have ∆ ⊂ ∆∗ by construction. Now, observe that ∆ satisfies the condition of ∆∗∗ in Lemma 12.2. Thus, we can apply Lemma 12.2 to conclude that Θ ⊢ ((η, ∆, H, ν, µ), s3 ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ) η ′′′ = η ′ , H ′′′ = H ′ , ν ′′′ = ν ′ , µ′′′ = ⊥ µ′ = evalReturn(∆′′′ , πr3 , µ3s ) Recall that the rewritten statement was of the form s′ = s3 ; x1 := µ3s . And so far we have evaluated the first part of s′ , i.e., the concrete execution of s3 . Now, we apply the concrete composition rule to evaluate the remaining part of s′ ; i.e., the assignment statement (x := µ3s ). Θ ⊢ ((η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ), x := µ3s ) ⇒c (η ′′′ , ∆4 , H ′′′ , ν ′′′ , µ′′′ ) observe that we have η ′′ == η ′′′ = η ′ , H ′′ = H ′′′ = H ′ , ν ′′ = ν ′′′ = ν ′ , µ′′ = ⊥ (conclusion 2). Now observe the following

• πr′ , must be the value true, by the construction of the the Θt (see Fig. 3). • πr′′ , πr3 = πr′ = true, this is because both the rename judgment for expression not the substitution judgment for expression change concrete values (see rule rename-val, and sub-val). • since πr3 = true, then according to the definition of evalReturn, we have that evalReturn(∆′′′ , πr3 , µ3s ) = µ′ , this then implies that µ3s must evaluate to µ′ , i.e., (∆′′′ , µ3s ) ⇝c µ′ • finally, observe that ∆4 = ∆′′′ [x1 ← µ′ ], while ∆′ = ∆[x1 ← µ′ ], and since we have that ∆ ⊆ ∆′′′ (using Lemma 4.2), and that ∆′′′ ⊆ ∆4 , then updating ∆ and ∆4 in the same way would maintain the same subset relation, i.e., ∆′ ⊂ ∆4 = ∆′′ (conclusion 1) Now, we want to show that ηs ⊆ η ′′′ . We have established from before that η ′′′ = η ′ , and from the statement of the lemma we have ηs ⊆ η, and from Lemma 4.2 η ⊆ η ′′′ , then by transitivity we can conclude that ηs ⊆ η ′′′ (conclusion 3). Finally, we have (∆) |= (∆s , π) from the premise, and we know from Lemma 6.1 that ∆ ⊆ ∆′ . Also, we have just shown that ∆′ ⊆ ∆′′ = ∆4 , then that means that evaluating π and all expressions mapped to within ∆s using ∆′′ , must reduce to the same values, thus we can conclude that (∆′′ ) |= (∆s , π) (conclusion 4). □

Lemma 12.4 (Inlining Transformation is Sound). If Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

47

Θt , ηs , ∆s ⊢ ((T, u), s) −→inline−wrap ((T ′ , u′ ), s′ ) ηs ⊆ η ∗ µ = evalReturn(∆′ , πr , µs ) (∆) |= (∆s , π ) Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ )

then ∆′ ⊆ ∆′′ η ′ = η ′′ , H ′′ = H ′ , ν ′′ = ν ′ , µ′′ = µ′ ηs ⊆ η ′′ µ∗ = evalReturn(∆′′ , πr , µs ) (∆′′ ) |= (∆s , π ) Proof The proof for the first four conclusions directly fall from applying Theorem 12.3. To show that µ∗ = evalReturn(∆′ , πr , µs ), recall that µs , πr has not been changed by the inlining transformation, moreover, we have proved that ∆′ ⊆ ∆′′ , thus evaluating µs and πr under ∆′′ must reduce to the same value µ∗ , same reasoning applies for showing that (∆′′ ) |= (∆s , π) holds. □

12.2 Method Inlining Properties This transformation assumes all the guaranteed properties from pervious transformations, γ -creation, remove final-returns, renaming and substitution transformations. In addition, it also assumes this property which is enforced by ensuring that the method transformation must have proceeded the method-inlining transformation (Property A.20). The method-transform is a static transformation that is done on all methods to populate Θt with the corresponding method statements, after applying γ -creation, early-returns elimination and remove final-returns transformations. Refer to section B for more detail about this static transformation. Now assuming we have that Θt , ηs , ∆s ⊢ ((T, u), s) −→inline−wrap ((T ′′ , u′ ), s′ ) such that ∆′s = ∅

Θt , ηs , ∆′s ⊢ ((T, u), s) −→inline ((T ′ , u′ ), s′ )

T ′′ = T ∪ T ′

Then we have the following guarantees

• Rewritten Statement s′ satisfies the SSA property (Property A.1). More formally, SSA(s′ ) holds. Proof We proceed by induction over the method-inlining transformation rules. Consider the rule inline-if. Then, from the induction hypothesis, we get that Γ ⊢ (µs , s1 ) →inline (µ′s , s′1 ) implies that the SSA property holds for s′1 , likewise, we get that Γ ⊢ (µs , s2 ) →inline (µ′s , s′2 ) implies that the SSA property holds for s′2 . This immediately gives that SSA(if e then s′1 else s′2 ) by definition of SSA.

48

Consider the rule inline-invoke. By the assumption that all invoked methods obey the SSA property, s obeys the SSA property. We then have the result that rename-wrap preserves SSA, and generates variable names that are tuples of an Id and a numeral (and as such are disjoint from x), so s′′ obeys the SSA property. Further, by definition of SSA, we have that any sub-statement of s′′ obeys SSA, so s′ obeys SSA. By the assumption that the input substitution transformation preserves the SSA property, s3 obeys the SSA property. By the inductive hypothesis, s4 obeys the SSA property. Consider inline-invoke-stop. In this case, the statement is not transformed, so the result holds trivially. Consider inline-return. SSA(skip) and SSA(return e) hold by definition of SSA, so SSA is preserved. □

13 T R7 : Field SSA Transformation In this transformation, field statements (getfield, putfield) are eliminated and replaced by a sequence of assignment statements that satisfies the SSA property. Fig. 14 shows the rules for the field transformation. The rules define two judgments. The judgment ∆s , Hs ⊢ ((T, P, ⊥), s) −→f ield ((T ′ , P ′ , p), s′ ) rewrites an IR statement s into s′ , where Hs is the symbolic heap, P is the path-subscript map tracking the latest update to each reference-field pair along the current local path in s, and p is the local path condition guarding reference-field updates. Initially, P agrees with Hs and p = ⊥. The updated map P ′ and flag p′ reflect the state of field accesses after rewriting. The wrapper judgment ∆s , Hs ⊢ ((I, O, T ), s) −→f ield-wrap ((I, O, T ′′ ), (addGets(P ); skip ; s′ ; skip ; addPuts(P ′ ))) is the entry point of the transformation, initializing P from Hs and triggering the field judgment on s, then wrapping the result with addGets(P ) and addPuts(P ′ ) to load and store field values at the boundaries of the rewritten region. More precisely, the rule field-wrap is the entry point for the field transformation. It initializes the field map P via initialP(Hs ), which assigns a fresh temporary variable t to each field-reference pair (r, f ) in the domain of Hs , representing the latest SSA variable carrying the value of that field along the current path. These fresh temporaries are added to T to produce T ′ , and the field transformation is then applied to s under T ′ and P , yielding a rewritten statement s′ , an updated field map P ′ , and a path condition p. The rule wraps s′ with addGets(P ) before and addPuts(P ′ ) after, which emit the necessary getfield and putfield instructions to load field values into their corresponding temporaries before execution and write them back after, respectively. The output temporary set T ′′ reflects all temporaries introduced during the transformation. The wrapping of s′ with addGets(P ) and addPuts(P ′ ) serves an important purpose beyond a single pass. Since field references are not always resolved to concrete references in one iteration, the transformation may require multiple fixpoint iterations until all reference variables are concretized. The wrapping captures the progress made in the current iteration: addGets(P ) records the getfield eliminations already performed, and addPuts(P ′ ) records the putfield eliminations, so that if a later iteration resolves a previously unresolved reference to a concrete one, the transformation can resume from where it left off rather than restarting from scratch. The skip statements

49

surrounding s′ in the residual serve as delimiters for pattern matching: in subsequent iterations, the field transformation is applied only to s′ and not to the entire residual statement. This is essential to avoid an infinite loop, as re-applying the transformation to addGets(P ) or addPuts(P ′ ) would cause their instructions to be treated as new field accesses requiring further elimination. The ⊥ flag in the field judgment ((T ′ , P, ⊥), s) −→f ield ((T ′′ , P ′ , p), s′ ) acts as a control flag that governs whether field elimination should continue. As long as the flag is ⊥, the transformation proceeds, eliminating getfield and putfield statements and updating P accordingly. However, upon encountering a method invocation, Rule field-invoke immediately flips the flag to ⊤ and halts further field elimination, flushing the current field map by prepending addPuts(P ) before the invoke statement. This is necessary because inlining the invoked method may introduce new concrete references that affect the SSA assignments of subsequent statements, and proceeding with elimination before those references are resolved would violate the sequentialization of SSA. Once the flag is set to ⊤, it propagates through compound statements: Rule field-if-2, field-if-3, field-if-4 and the corresponding sequential composition rule (not shown) propagate ⊤ to prevent any further elimination in the remainder of the statement, ensuring that field elimination resumes only in the next fixpoint iteration after inlining has been applied. The core of the field transformation lies in the elimination of getfield and putfield statements, replacing them with simple variable assignments using the field map P . Rule field-put eliminates a putfield instruction by introducing a fresh temporary variable t and updating the field map to P ′ = P [(r, f ) ← t], recording that t now carries the latest value of the field-reference pair (r, f ). The putfield is replaced by the assignment t := e. Rule field-get eliminates a getfield instruction by looking up the latest temporary t associated with (r, f ) in P and replacing the getfield with the assignment x := t, leaving P unchanged. Both rules require that r is a concrete reference, i.e., r ∈ R, if references has been resolved to their concrete values, otherwise, no rewriting is performed (field-put-var and field-get-var rules, see our technical report [33] for complete set of rules). Finally, the rule field-if-1 handles the case where field elimination succeeds completely in both branches of a conditional, i.e., neither branch encounters a method invocation. Each branch is processed independently under the same initial field map P , yielding rewritten statements s′1 and s′2 and updated field maps P ′ and P ′′ respectively. Since the two branches may assign different temporaries to the same field-reference pair (r, f ), the maps P ′ and P ′′ must be reconciled after the conditional. This is handled by the merge function, which compares P ′ and P ′′ and, for each field-reference pair (r, f ) where the two branches disagree, introduces a fresh temporary t assigned to γ (e, t1 , t2 ), where t1 = P ′ (r, f ) and t2 = P ′′ (r, f ) are the temporaries from the left and right branches respectively. The merge proceeds recursively until all disagreements are resolved, producing a unified field map P̂ and a sequence of γ -assignments ŝ appended after the conditional. If both branches produce identical field maps, merge returns skip and leaves P unchanged.

50

13.1 Field Transformation is Sound In this section, we discuss the soundness of the Field Transformation. We first present a consistency properties over the path-subscript map, then we show the soundness of the recursive judgment followed by the soundness of the wrapper judgment. For any path-subscript map P , local variable mapping ∆, and a Heap, we define a P -Heap consistency relation (P, H ′ , ∆′ ) ⋊ H ′ for all reference and field pairs (r, f ), as

( ′

′

(P, H , ∆ ) ⋊ H

iff

∀(r, f ) ∈ Dom(H ).H (r, f ) =

∆′ (P (r, f )) H ′ (r, f )

if (r, f ) ∈ Dom(P ) otherwise

Intuitively, the relation (P, H ′ , ∆′ ) ⋊ H defines when a concrete heap H is consistent with a symbolic field map P , a base heap H ′ , and a local variable mapping ∆′ . Specifically, for each field-reference pair (r, f ), H must agree with the value of the corresponding temporary variable P (r, f ) in ∆′ if (r, f ) is tracked in P , and fall back to the base heap H ′ otherwise. A key property of the merge function is that it preserves the P-Heap consistency relation across both branches of a conditional. Intuitively, if both branches independently maintain P-Heap consistency with their respective field maps P1 and P2 , then the γ -assignments produced by merge yield a unified field map P̂ that remains consistent with the concrete heap H , regardless of which branch was taken. This is formalized in Lemma 13.1.

Lemma 13.1. Dom(P1 ) = Dom(P2 ) (P1 , H1′ , ∆1 ) ⋊ H1 (P2 , H2′ , ∆2 ) ⋊ H2 (ŝ, P̂ ) = merge(e, P1 , P2 ) ˆ , H ′ , ν, µ) (Θ ⊢ ((η, ∆, H ′ , ν, µ), ŝ) ⇒c (ηs , ∆ ∀x.isU se(x, e) =⇒ ∆1 (x) = ∆2 (x) ∆ ⊢ e ⇝c b b ∈ {true, f alse} ( (∆1 , H1′ , H1 ) if b=true (∆, H ′ , H ) = (∆2 , H2′ , H2 ) otherwise then ˆ ⋊H (P̂ , H ′ , ∆) Proof We will prove this lemma using induction over the recursive invocation of the merge(e, P1 , P2 ) function. Observe that the merge function is terminating because on each recursive call the number of differences between the two merged path-mappings, i.e., P1 , P2 decreases. First, consider the case when P1 = P2 = P . Let H1 , H1′ , H2 , H2′ and ∆1 , ∆2 be instances of a concrete heap and local variable mapping such that (P, H1′ , ∆1 )⋊H1 and (P, H2′ , ∆2 )⋊H2 . At this point, we know that the merging will not introduce new changes, i.e., (skip, P ) =

51

ˆ ⋊ H. There are merge(e, P, P ), where ŝ = skip, and P̂ = P . We want to show that (P̂ , H ′ , ∆) two possibilities depending on the evaluation of e. The first case is when ∆1 ⊢ e ⇝c true, and b = true. In this case, we have that ((η, ∆1 , H1 , ν, µ), skip) ⇒c (η, ∆1 , H1 , ν, µ). But we have shown that when (P, H1′ , ∆1 ) ⋊ H1 . Similarly, for the second case where b = f alse, we have that ((η, ∆2 , H2 , ν, µ), skip) ⇒c (η, ∆2 , H2 , ν, µ), but also we have (P, H2′ , ∆2 ) ⋊ H2 , ˆ ⋊ H. from the premise of the theorem. Thus, we have shown that inn either case (P̂ , H ′ , ∆) Next, consider the case where P1 ̸= P2 . Then, this means that there exist some (r, f ) pair whose mapped values are different in both maps, i.e., P1 (r, f ) ̸= P2 (r, f ). Let t1 = P1 (r, f ), and t2 = P2 (r, f ), where we know that t1 ̸= t2 . In this case, according to the merge definition, a new fresh variable t is created and both maps are updated to create two new maps P1′ and P2′ with one less difference. More formally, we have that P1′ = P1 [(r, f ) ← t], and P2′ = P2 [(r, f ) ← t]. Then, the merge function is recursively called over the remaining differences in P1′ and P2′ such that (s′r , Pr′ ) = merge(e, P1′ , P2′ ). And finally, the function returns the pair (t := γ(e, t1 , t2 ); s′r , Pr′ ). Here ŝ = t := γ(e, t1 , t2 ); s′r , and P̂ = Pr′ . Let ∆1 , ∆2 be two concrete local mapping, and H1 , H2 be two concrete heap mappings, such that (P1 , H1′ , ∆1 )⋊ H1 , and (P2 , H2′ , ∆2 ) ⋊ H2 . Then, we want to show that if (Θ ⊢ ((η, ∆1 , H ′ , ν, µ), ŝ) ⇒c ˆ H ′ , ν, µ), then (P̂ , H1′ , ∆1 ) ⋊ H1 , if ∆1 ⊢ e ⇝c b, and where b = true. Similarly, we (η, ∆, ˆ H ′ , ν, µ), then (P̂ , H2′ , ∆2 ) ⋊ H2 , if want to show that if Θ ⊢ ((η, ∆2 , H ′ , ν, µ), ŝ) ⇒c (η, ∆, ∆2 ⊢ e ⇝c b, and where b = f alse. To show this proof, will first show that the induction induction hypothesis holds, before we can apply it. First, observe that Dom(P1′ ) = Dom(P2′ ) since Dom(P1 ) = Dom(P2 ) from the premise, also P1′ and P2′ are created from P1 and P2 , respectively, by updating an exiting mapping and thus not changing their domains. Next, let ∆1 be defined by Θ ⊢ ((η, ∆1 , H1′ , ν, µ), t = γ(e, t1 , t2 )) ⇒c (η, ∆′1 , H1′ , ν, µ). We also know that ∀x.isU se(x, e) =⇒ ∆1 (x) = ∆2 (x) and that ∆ ⊢ e ⇝c b ,where b ∈ {true, f alse}. Now assume that b = true. In this case we know that ∆′1 = ∆1 [t ← ∆1 (t1 )], using the γ-expression rule from the concrete semantics. Now observe that (P1′ , H1′ , ∆′1 ) ⋊ H1 holds, where H1′ = H1 , since no change on the heap can occur with the assignment statement. Moreover, observe that we have that (P1 , H1 , ∆1 ) ⋊ H1 by the statement of the theorem. In addition, we know that the only change P1′ has over P1 is the update of the single referencefield pair P1′ = P1 [(r, f ) ← t], which will be mapped to the value of t1 in ∆′1 . But since we have (P1 , H1 , ∆1 ) ⋊ H1 , then we know that it must be H1 (r, f ) = ∆1 (P1 (t1 )) = ∆′1 (P1′ (t)) = H1′ (r, f ). Because of the same reasoning, in the case where b = f alse, we will have that (P2′ , H2′ , ∆′2 ) ⋊ H2 , where H2′ = H2 , again because no change on the heap can occur with the assignment statement. Next observe that the evaluation of e in both ∆1 and ∆2 are the same, i.e, ∆1 ⊢ e ⇝c b, and ∆2 ⊢ e ⇝c b. This is because we have that ∀x.isU se(x, e) =⇒ ∆1 (x) = ∆2 (x), by the statement of the theorem, and we also know the newly assigned t is fresh, and thus previous variable mappings remain the same. Finally, observe that (Θ ⊢ ((η, ∆′ , H ′ , ν, µ), s′r ) ⇒c (η, ∆′′ , H ′ , ν, µ), then it must be ˆ since ŝ = t := γ(e, t1 , t2 ); s′r , and recall that ∆′ must contain the mapping t, that ∆′′ = ∆, ′ i.e., ∆1 = ∆1 [t ← t1 ], or ∆′2 = ∆2 [t ← t2 ]. At this point, we have shown that the induction hypothesis hold, and thus we can conclude ˆ ⋊ H hold. But observe here that Pr′ = P̂ since Pr′ will include the mapping that (Pr′ , H ′ , ∆) all the mappings from the induction hypothesis in addition to the (r, f ) ← t, which we have ˆ ⋊ H. □ shown that satisfies the Bigrtimes relation. Thus, we can conclude that (P̂ , H ′ , ∆)

Before establishing the soundness of the field transformation, we state two preliminary results. Corollary 13.2 establishes a domain invariant on the field map P : after

52

any application of the field judgment, either the flag is set to ⊤ and P ′ is empty, reflecting that field elimination was halted by a method invocation, or the flag remains ⊥ and the domain of P ′ is preserved and equals that of Hs . This ensures that P always tracks exactly the set of field-reference pairs in Hs throughout the transformation. Lemma 13.3 establishes that the field judgment preserves the generalized SSA property: if s satisfies SSA(s) before the transformation, then the rewritten statement s′ satisfies SSA(s′ ) after. These two results together provide the necessary foundations for the soundness argument of the field transformation.

Corollary 13.2. [Either P is empty, or its domain is the same to the domain of Hs ] If ∆s , Hs ⊢ ((T, P, p), s) −→f ield ((T ′ , P ′ , p′ ), s′ ) then p′ = ⊤ ∧ P ′ = ∅ or p′ = ⊥ ∧ Dom(P ) = Dom(Hs ) = Dom(P ′ ) Proof It is easy to see why this theorem is true. Initially, the field-wrap rule triggers the ←f ield judgment, which sets up P to have the same domain as Hs . Next, field-no-op, field-get-var, field-put-var, field-invoke, field-if-2, field-if-3, and field-if-4 rules, all end up with p′ = ⊥, but we can also see that in these cases P ′ = ∅. For field-get, we can clearly see that P ′ is the same as P , while p′ = ⊥, so the remark holds here too. The rules that introduce a change on P ′ that is different from P includes put-field, field-comp and field-if-1. For put-field, we P ′ is created from P as P ′ = P [(r, f ) ← t], where r, f are a reference, and field pair, while t is a fresh temporary variable. But since r, f already exists in P , then P ′ is actually updating the mapping of an existing r, f pair, rather than introducing a new entry. Thus in this case we have that Dom(P ) = Dom(Hs ) = Dom(P ′ ). In the field-comp rule, the theorem hold straightforward by using induction over the judgments used to transform s1 , and s2 . Finally, for field-if-1 rule, we have that ∆s , H s ⊢ ((T, P, p), if e then s1 else s2 ) −→f ield ((T2 , P̂ , p̂), if e then s′1 else s′2 ; ŝ), such that (ŝ, P̂ ) = merge(e, P1 , P2 ), ∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T1 , P1 , p1 ), s′1 ), ∆s , Hs ⊢ ((T1 , P, ⊥), s2 ) −→f ield ((T2 , P2 , p2 ), s′2 ), p1 = p2 = p = ⊥. Here we have P ′ = P̂ , p′ = p̂. By induction, we know that Dom(P1 ) = Dom(P2 ) = Dom(P ) = Dom(Hs ). In this case, from the rule we directly have that p′ = ⊥. Then, we want to show that Dom(P ′ ) = Dom(P̂ ) = Dom(Hs ). Here, we know that P̂ is the result of merge(e, P1 , P2 ). But, from the definition of the merge function, the function either returns the same mapping if P1 = P2 , and it is clear then that Dom(P̂ ) = Dom(P ), or it create a new temporary variable t such that P̂ (r, f ) = t, but we know that r, f must have existed in the domain of either P1 or P2 . Then, we can conclude that Dom(P̂ ) = Dom(P1 ) = Dom(P2 ) = Dom(P ) = Dom(Hs ). □

Lemma 13.4 establishes the soundness of the field transformation. It states that executing the original statement s on a concrete state (∆, H ) and executing the rewritten statement s′ on an enriched state (∆′ , H ′ ) that is P-Heap consistent with H produce

53

the same observable behavior, i.e., the same control state η , return value µ, and path condition ν . Furthermore, the local variable mapping is preserved in the sense that ∆′′ ⊆ ∆′′′ , and the P-Heap consistency relation is maintained after execution, ensuring that the rewritten heap H ′′′ remains consistent with the updated field map P ′ .

Lemma 13.3. [The judgment →f ield maintains the SSA property] If ∆s , Hs ⊢ ((T, P, p), s) −→f ield ((T ′ , P ′ , p′ ), s′ ) isSSA(s) then isSSA(s′ ) Proof Rules field-no-op and field-assign hold trivially since, from the hypothesis, we have isSSA(s), and s does not change with the rewriting. Now, consider the rules field-comp, field-if-2. For these rules, we can use straightforward induction over the premises of the rules to conclude that the rewritten statement maintains the SSA property. Next, consider the field-put rule, here s = put f ield(r, f, e), and s′ = t := e. But note here that the newly added variable t, is already fresh (it cannot clash with existing variables), thus it cannot clash with any of the defined/assigned variables. Next, consider the field-get and field-invoke, in both of these rule no new assignments are introduced, thus, the SSA property is maintained there too. Now, consider the more interesting case of field-if-1. In this case, new statements are added in ŝ in the form of a sequential composition of assignment statements of the form t := γ(e, t1 , t2 ). According to the definition of the merge, t must be fresh, i.e., cannot clash with any of the existing variables. Finally, consider the field-if-3 and field-if-4. In both of these rules, the if-statement is rewritten, where one of its sides is sequentially composed with a sequence of get-field statements; i.e., (s′2 ; addP uts(P ′′ )), and (s′1 ; addP uts(P ′ )). But, observe here that s′2 and s1 are both in SSA form by using induction. Moreover, the put-field statements that results from addP uts function, do not define/introduce new assignment statements. Thus, in both cases the rewritten statement also maintains the SSA property. □

Lemma 13.4. [Recursive Field Rewriting is Sound] If ∆ ⊆ ∆′ (P, H ′ , ∆′ ) ⋊ H ∆s , Hs ⊢ ((T, P, p), s) −→f ield ((T ′ , P ′ , p′ ), s′ ) (Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ) (Θ ⊢ ((η, ∆′ , H ′ , ν, µ), s′ ) ⇒c (η ′′′ , ∆′′′ , H ′′′ , ν ′′′ , µ′′′ ) then η ′′ = η ′′′

ν ′′ = ν ′′′ ∧ µ′′ = µ′′′ ∆′′ ⊆ ∆′′′ (P ′ , H ′′′ , ∆′′′ ) ⋊ H ′′ ∧

54

(1) (2) (3)

Proof We proof the lemma using structural induction over the statement s. Consider the field-no-op rule. In this case the lemma statement holds trivially as s = s′ , i.e., the statement s has not been rewritten, and thus we will have that ηs′′ = ηs′′′ , µ′′ = µ′′′ , ∆′′ ⊆ ∆′′′ and H ′′ = H ′′′ . We also have that P = P ′ = ∅, which means that the second case of the (P ′ , H ′′′ , ∆′′′ ) ⋊ H ′′ applies, i.e., (∅, H ′′ , ∆′′′ ) ⋊ H ′′ . field-put We have ∆s , Hs ⊢ ((T, P, ⊥), put f ield(r, f, e)) −→f ield ((T ∪ {t}, P ′ , ⊥), t := e), where r ∈ R and P ′ = P [(r, f ) ← t], where t is a fresh SSA variable. Executing concretely the put-field statement we get Θ ⊢ ((η, ∆, H, ⊥), put f ield(r, f, e)) ⇒c (η, ∆, H[(r, f ) ← v2 ], ⊥), such that ∆ ⊢ e ⇝c v2 , ∆′′ = ∆, and H ′′ = H[(r, f ) ← v2 ]. From the hypothesis we have ∆′ , and H ′ , such that (P, H ′ , ∆′ ) ⋊ H. Executing the rewritten statement concretely, we get Θ ⊢ ((η, ∆′ , H ′ , ⊥), t := e) ⇒c (η, ∆′′′ , H ′′′ , ⊥), where ∆′′′ = ∆′ [t ← v1 ], ∆′ ⊢ e ⇝c v1 , and H ′′′ = H ′ . Here, we know that , η ′′′ = η = η ′′ , µ′′′ = µ = µ′′ (since H, η, and µ do not change). This proves the third conclusion (1) in our theorem. To show conclusion (2), observe here that the rewriting has not changed the expression e. Moreover, here we are evaluating e in ∆′ , where we know that ∆ ⊆ ∆′ , by the hypothesis of the lemma. Moreover, we know the SSA property is maintained (assume 13.3). Thus, we can conclude that e will evaluate to the same value, more precisely, v2 = v1 , and since t is fresh, i.e., t ∈ / Dom(∆′ ), and that the only change between ∆′′′ and ∆′ is the new mapping for t, then we must have that have ∆′′ ⊆ ∆′′′ . Finally, to show conclusion (3), observe that from remark 13.2, we know that the domain of P ′ , is the same as the domain of P , and we have from the hypothesis that (P, H ′ , ∆′ ) ⋊ H. Moreover it must be that an existing reference-field pair in P ′ was updated rather than a new one was added. Thus, we can observe here that ∆′′′ (t) = v1 = v2 = H ′′ (r, f ). Thus, we can also conclude that (P ′ , H ′′′ , ∆′′′ ) ⋊ H ′′ . field-get We have ∆s , Hs ⊢ ((T, P, ⊥), get f ield(x, z, f )) −→f ield ((T, P, ⊥), x := t), where P ′ = P, T ′ = T, r1 = ∆s (z), r1 ∈ R, and t = P (r1 , f ). Executing the original statement concretely we get Θ ⊢ ((η, ∆, H, ⊥), get f ield(x, z, f )) ⇒c (η, ∆[x ← v2 ], H, ⊥), such that ∆ ⊢ z ⇝c r2 , and v2 = H(r2 , f ). Since we have that (∆, H) |= (∆s , Hs , π) (assume A.9), and since we assume that all references must be concrete values (assume A.21), then it must be the case that r1 = r2 , which we will refer to as just r. Observe that ηs′′ = ηs , H ′′ = H, ∆′′ = ∆[x ← v2 ], ν ′′ = ν and µ′′ = µ. Let us assume that we have ∆′ , H ′ , such that (P, H ′ , ∆′ )⋊H, and ∆ ⊆ ∆′ . Now, executing the rewritten statement, we get Θ ⊢ ((η, ∆′ , H ′ , ⊥), x := t) ⇒c (η, ∆′ [x ← v2 ], H ′ , ⊥), such that v2 = ∆′ (t), ∆′′′ = ∆′ [x ← v2 ]. and H ′′′ = H ′ . Here, we know that , η ′′′ = η = η ′′ , µ′′′ = µ = µ′′ (since H, ηs , and µ do not change). This proves the third conclusion (1) in our theorem. Now, bserve that since we have that ∆ ⊆ ∆′ , and ∆′′ = ∆[x ← v1 ], and ∆′′′ = ∆′ [x ← v2 ]. Moreover, we can conclude that v1 = v2 . This is because, we have that v1 = H(r, f ) = ∆′ (P (r, f )) = v2 , where the second equality comes from (P, H ′ , ∆′ ) ⋊ H, and the fact that (r, f ) ∈ Dom(P ). In other words, P must contain a mapping for (r, f ) pair, which when looked up in ∆′ , it must be equal to the value of the pair in H, i.e., H(r, f ), consequently, it must be the case that (P ′ , H ′′′ , ∆′′′ ) ⋊ H ′′ (conclusion 3 holds). Finally, due to the SSA property we know that x ∈ / Dom(∆) and similarly x ∈ / Dom(∆′ ). Moreover, we have shown ′′ ′′′ that v1 = v2 , thus, we can conclude that ∆ ⊆ ∆ , which proves conclusion 2. field-invoke, field-put-var, field-get-var We will show the proof for field-invoke, but all three rules field-invoke, field-put-var, and field-get-var are follow the same proof structure. In general, the proof of this rule follows from the observation that the field-puts statement, generated by addPuts(P), copies the contents of P into the heap without altering any other

55

environment variable. By the induction hypothesis, we have (P, H ′ , ∆′ ) ⋊ H, which implies that if P is non-empty, then for every reference-field pair, the corresponding temporary variable name holds a concrete value equal to that of the reference-field pair in the heap. Consequently, writing back the values of P into H reproduces H itself. Therefore, the invoke statement is executed in exactly the same environment as the original statement, without introducing any changes. As a result, the final state remains identical, and thus all conclusions of the lemma continue to hold. field-comp Consider the field-comp rule. Here we will use similarity between the conclusions of the lemma and the two similar premises to show how the property is maintained between multiple statements. Here, we have s = s1 ; s2 , such that ∆s , Hs ⊢ ((T, P, ⊥), s1 ; s2 ) −→f ield ((T ′ , P2 , p2 ), s′1 ; s′2 ), where ∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T1 , P1 , p1 ), s′1 ), and ∆s , Hs ⊢ ((T1 , P1 , p1 ), s2 ) −→f ield ((T2 , P2 , p2 ), s′2 ). Note that here we have P ′ = P2 , p′ = p2 . Observe here that composition-ret cannot apply after running the remove final return transformation (assume A.16). Thus, the only concrete compositional rule that can apply at this point is composition. Here, we get Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ; s2 ) ⇒c (η 5 , ∆5 , H 5 , ν 5 , µ5 ), where Θ ⊢ ((η, ∆, H, ⊥), s1 ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , ⊥), and Θ ⊢ ((η 4 , ∆4 , H 4 , ν 4 , ⊥), s2 ) ⇒c (η 5 , ∆5 , H 5 , ν 5 , µ5 ). Let us assume we have ∆′ , H ′ such that, ∆ ⊆ ∆′ , and (P, H ′ , ∆′ ) ⋊ H. Now executing the s′1 of the rewritten statement we get Θ ⊢ ((η, ∆′ , H ′ , ⊥), s′1 ) ⇒c (η 6 , ∆6 , H 6 , ν 6 , µ6 ). Using the induction hypothesis at s1 , we know that it must be that η ′′ = η 5 , ∆′′ = ∆5 , H ′′ = H 5 , ν ′′ = ν 5 and µ′′ = µ5 , and that (P1 , H 6 , ∆6 ) ⋊ H 4 , ∆4 ⊆ ∆6 , and that η 6 = η 4 , ν 6 = ν 4 , and µ6 = µ4 = ⊥. Thus, executing s′2 in this concrete state we get Θ ⊢ ((η 6 , ∆6 , H 6 , ν 6 , ν 6 ), s′2 ) ⇒c (η 7 , ∆7 , H 7 , ν 7 , µ7 ). Again using the induction hypothesis at s2 with the premises (P1 , H 6 , ∆6 ) ⋊ H 4 , and ∆4 ⊆ ∆6 , then we know that it must be the case that (P2 , H 7 , ∆7 ) ⋊ H 5 , and ∆5 ⊆ ∆7 , η 7 = η 5 , ν 7 = ν 5 and µ7 = µ5 . But, this then mean that Θ ⊢ ((η, ∆, H, ⊥), s′1 ; s′2 ) ⇒c (η 7 , ∆7 , H 7 , µ7 ), where ∆′′′ = ∆7 , H ′′′ = H 7 . Now, we have just shown that (P ′ , H ′′′ , ∆′′′ ) ⋊ H ′′ (conclusion 3), and that ∆′′ = ∆5 ⊆ ∆7 = ∆′′′ (conclusion 2). And finally that, η ′′′ = η 7 = η 5 = η ′′ , ν ′′′ = ν 7 = ν 5 = ν ′′ and µ′′′ = µ7 = µ5 = µ′′ (conclusion 1). field-if-1 Now, consider the field-if-1 rule. In this case, we have s = if e then s1 else s2 , such that ∆s , Hs ⊢ ((T, P, ⊥), if e then s1 else s2 ) −→f ield ((T ′′ , P̂ , ⊥), if e then s′1 else s′2 ; ŝ), where (ŝ, P̂ ) = merge(e, P1 , P2 ), ∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T ′ , P1 , ⊥), s′1 ), and ∆s , Hs ⊢ ((T ′ , P, ⊥), s2 ) −→f ield ′′ ′ ((T , P2 , ⊥), s2 ). Note that here we have P ′ = P̂ , p′ = ⊥. There are two concrete execution rules that can apply depending on whether the condition of the if-statement evaluates to true or false. We will show the proof argument for the former, but the latter follows a very similar argument. Now, consider executing the original statement using the both composition and if-phi-true rule, we get for the first statement Θ ⊢ ((η, ∆, H, ⊥), if e then s1 else s2 ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 ), where µ4 = ⊥, ∆ ⊢ e ⇝c true, and Θ ⊢ ((η, ∆, H, µ), s1 ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 ). Here we have that ηs′′ = ηs4 , ∆′′ = ∆4 , H ′′ = H 4 , ν ′′ = ν 4 , µ′′ = µ4 = ⊥. Now consider executing the rewritten statement concretely. Let us assume we have ∆′ , H ′ such that, ∆ ⊆ ∆′ , and (P, H ′ , ∆′ ) ⋊ H. Due to the subset relationship between ∆ ⊆ ∆′ , we know that the expression e must evaluate to the same value true, i.e., ∆′ ⊢ e ⇝c true, and therefore, rule if-phi-true will still apply. Here we have Θ ⊢ ((η, ∆′ , H ′ , µ), s′1 ) ⇒c (η 5 , ∆5 , H 5 , ν 5 , µ5 ), where µ5 = ⊥. Using the induction hypothesis at s1 , we know that (P1 , H 5 , ∆5 ) ⋊ H 4 , and that η 4 = η 5 , ν 4 = ν 5 , µ4 = µ5 . Thus, we can evaluate ŝ using the remaining part of the sequential composition, i.e.; Θ ⊢ ((η 5 , ∆5 , H 5 , ν 5 , µ5 ), ŝ) ⇒c (η 6 , ∆6 , H 6 , ν 6 , µ6 ). Note that, here we have that ∆′′′ = ∆6 , and H ′′′ = H 6 . However, since by definition ŝ is composed of a sequence of assignment statements, then no heap changes can

56

ever occur. Thus we know that ∆′′ = ∆4 ⊆ ∆6 = ∆′′′ . Also, we can conclude that η ′′′ = η 6 = ηs5 = ηs4 = ηs′′ , ν ′′′ = ν 6 = ν 5 = ν 4 = ν ′′ , µ′′′ = µ6 = µ5 = µ4 = µ′′ (conclusion 1). Observe that H ′′′ = H 6 = H 5 , Now, we want to show that (P̂ , H 5 , ∆6 ) ⋊ H 4 , but this falls directly from applying lemma 13.1, where ∆ ⊢ e ⇝c b, b = true (conclusion 3). field-if-2 Here, s = ∆s , Hs ⊢ ((T, P, ⊥), if e then s1 else s2 ) −→f ield ((T ′′ , ∅, ⊤), if e then s′1 else s′2 ), where ∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T ′ , ∅, ⊤), s′1 ), and ∆s , Hs ⊢ ((T ′ , P, ⊥), s2 ) −→f ield ((T ′′ , ∅, ⊤), s′2 ). Note that here we have P ′ = ∅, p′ = ⊤. There are two concrete execution rules that can apply depending on whether the condition of the if-statement evaluates to true or false. We will show the proof argument for the former, the proof of the latter follows a very similar argument. Now, consider executing the original statement using the if-phi-true rule, we get for the first statement Θ ⊢ ((η, ∆, H, ⊥), if e then s1 else s2 ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 ), where µ4 = ⊥, ∆ ⊢ e ⇝c true, and Θ ⊢ ((η, ∆, H, µ), s1 ) ⇒c (η, ∆4 , H 4 , ⊥). Here we have that η ′′ = η 4 , ν ′′ = ν 4 , µ′′ = µ4 , and ∆′′ = ∆4 , H ′′ = H 4 . Now, consider executing the rewritten statement concretely. By hypothesis, we have ∆′ , H ′ such that, ∆ ⊆ ∆′ , and (P, H ′ , ∆′ ) ⋊ H. Due to the subset relationship between ∆ ⊆ ∆′ , we know that the expression e must evaluate to the same value true, i.e., ∆′ ⊢ e ⇝c true, and therefore, rule if-phi-true will still apply. Here we have Θ ⊢ ((η, ∆′ , H ′ , µ), s′1 ) ⇒c (η 5 , ∆5 , H 5 , ν 5 , µ5 ), where µ5 = ⊥. Note, that we have that η ′′′ = η 5 , ν ′′′ = ν 5 , µ′′′ = µ5 , ∆′′′ = ∆5 , and H ′′′ = H 5 . Using the induction hypothesis at s1 , we know that η ′′′ = η 5 = ηs4 = ηs′′ , ν ′′′ = ν 5 = ν 4 = ν ′′ and µ′′′ = µ5 = µ4 = µ′′ (conclusion 1). (P ′ = ∅, H 5 , ∆5 ) ⋊ H 4 (conclusion 3) and ∆4 ⊆ ∆5 (conclusion 2), which are what we want to prove. field-if-3 Here, we have that ∆s , Hs ⊢ ((T, P, ⊥), if e then s1 else s2 ) −→f ield ((T2 , ∅, ⊤), if e then (s′1 ; addP uts(P1 )) else s′2 ) where ∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T1 , P1 , ⊥), s′1 ), and ∆s , Hs ⊢ ′ ((T1 , P, ⊥), s2 ) −→f ield ((T2 , ∅, ⊤), s2 ). Note that here we have P ′ = ∅, p′ = ⊤. There are two concrete execution rules that can apply depending on whether the condition of the if-statement evaluates to true or false. We will show the proof argument for the latter, but the former follow a very similar argument to that of the field-if-2 rule. Now consider executing the original statement using the if-phi-true rule, we get for the first statement Θ ⊢ ((η, ∆, H, ⊥), if e then s1 else s2 ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 ), where µ4 = ⊥, ∆ ⊢ e ⇝c true, and Θ ⊢ ((η, ∆, H, µ), s1 ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 ). Here we have that η ′′ = η 4 , ∆′′ = ∆4 , H ′′ = H 4 , ν ′′ = ν 4 , µ′′ = µ4 . Now, consider executing the rewritten statement concretely. By hypothesis, we have ∆′ , H ′ such that, ∆ ⊆ ∆′ , and (P, H ′ , ∆′ ) ⋊ H. Due to the subset relationship between ∆ ⊆ ∆′ , we know that the expression e must evaluate to the same value true, i.e., ∆′ ⊢ e ⇝c true, and therefore, rule if-phi-true will still apply. Now, we have to execute the then-side of the rewritten statement; i.e. s′1 ; addP uts(P1 ). Here, we have Θ ⊢ ((η, ∆′ , H ′ , µ), s′1 ) ⇒c (η 5 , ∆5 , H 5 , ν 5 , µ5 ), where µ5 = ⊥. Using the induction hypothesis at s1 , we know that (P1 , H 5 , ∆5 ) ⋊ H 4 . Now, evaluating the addP uts(P1 ), we get Θ ⊢ ((η 5 , ∆5 , H 5 , ν 5 , µ5 ), addP uts(P1 )) ⇒c (η 6 , ∆6 , H 6 , ν 6 , µ6 ). However, according to the definition of the addP uts(P1 )(see Fig. 14), H6 will be supplemented with the same reference-field mappings as H4 , for all reference-field pairs that exists in P1 , since we have that (P1 , H 5 , ∆5 )⋊H 4 initially assumed. Thus, H6 = H4 . Also observe that the addP uts(P1 ) does not introduce any side effects on the local mapping, since the addP uts(P1 ) is a sequence of put f ield statements, and ηs′′′ = ηs6 = ηs5 = ηs′′ , ν ′′′ = ν 6 = ν 5 = ν ′′ , µ′′′ = µ6 = µ5 = µ′′ (conclusion 1), and ∆′′′ = ∆6 = ∆5 = ∆′′ (conclusion 2). Thus, formally we can conclude that Θ ⊢ ((η, ∆5 , H 5 , ⊥), addP uts(P1 )) ⇒c (η, ∆5 , H 4 , ⊥), which implies that (∅, H 4 , ∆5 ) ⋊ H 4 holds (conclusion 3). The proof for the field-if-4 follows the same argument as this one (the field-if-3 rule).

57

□

We now lift the soundness result from the recursive field judgment to the toplevel wrapper. Theorem 13.5 establishes that executing the original statement s and its field-transformed counterpart s′′ from the same concrete state produce the same observable behavior: the same control state η , path condition ν , and return value µ. Furthermore, the local variable mapping is extended consistently, i.e., ∆′ ⊆ ∆′′ , and the heap is preserved, i.e., H ′ = H ′′ , reflecting that all heap accesses have been internalized as variable assignments by the transformation.

Theorem 13.5 (Field Transformation is Sound). (∆, H ) |=H (∆s , Hs , π ) ∆s , Hs ⊢ ((I, O, T ), s) −→f ield−wrap ((I, O, T ′ ), s′′ ) Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) Θ ⊢ ((η, ∆, H, ν, µ), s′′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ )

then η ′ = η ′′

∧

ν ′ = ν ′′ ∧ ∆′ ⊆ ∆′′ H ′ = H ′′

µ′ = µ′′

(1) (2) (3)

Proof First, we have by applying the field-wrap that p = ⊥, T ′ = T ∪ Range(P ) such that Hs ⊢ ((T ′ , P, ⊥), s) −→f ield ((T ′′ , P ′ , p), s2 ). Next, observe that the obtained s′′ can be understood in three parts, i.e., s′′ = s1 ; s2 ; s3 , such that s1 = addGets(P ); skip;, and s3 = skip; addP uts(P ′ ). This break down is unique since addGets and addP uts cannot contain a skip-statement. Now, executing concretely the first part of s′′ , we get Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ) Observe that here we have η ′ = η1 , ∆′ = ∆1 , H ′ = H1 , ν ′ = ν1 , µ′ = µ1 . Since addGets(P ) is defined as addGets(P ) = get f ield(t1 , r1 , f1 ); . . . ; get f ield(tn , rn , fn ) ∀((ri , fi ), ti ) ∈ P, 1 ≤ i ≤ n, n = |P |. Then, we know that the concrete execution of s1 only affects the local variable mapping. Therefore, we know that η1 = η, H1 = H, ν1 = ν and µ1 = µ. Because P = initialP (Hs ) each ti is a fresh variable, i.e., distinct from any variable in ∆. From Corollary 13.2, we know that Dom(H) = Dom(Hs ) = Dom(P ) and from the premise of the theorem we have (∆, H) |= (∆s , Hs , π). Therefore, it must be ∆1 = ∆[t1 ← v1 , . . . , tn ← vn ], for each (ri , fi ) ∈ Dom(H) such that ti = P (ri , fi ) and vi = H(ri , fi ). This implies that we must have ∆ ⊆ ∆1 . Also, recall that (P, H ∗ , ∆∗ ) ⋊ H is defined as ( ∗

∗

(P, H , ∆ ) ⋊ H

iff

∀(r, f ) ∈ Dom(H).H(r, f ) =

58

∆∗ (P (r, f )) H ∗ (r, f )

if (r, f ) ∈ Dom(P ) otherwise

Let us choose H ∗ = H, and ∆∗ = ∆1 . Let (ri , fi ) be any pair in the domain of H. Because the Dom(H) = Dom(P ) the first case applies. Let ti = P (ri , fi ), then ∆1 (ti ) = v = H(ri , fi ), since ∆1 is known to be equal to ∆[t1 ← v1 , . . . , tn ← vn ]. Thus the equality in the definition of (P, H, ∆1 ) ⋊ H holds. Now, when concretely executing s2 we can apply Lemma 13.4 for the soundness of the recursive judgment for the field transformation, such that we have p=⊥ ∆1 ⊆ ∆ 1 (P, H, ∆1 ) ⋊ H ∆s , Hs ⊢ ((T, P, p), s2 ) −→f ield ((T ′ , P ′ , p′ ), s′2 ) (Θ ⊢ ((η, ∆1 , H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ) (Θ ⊢ ((η, ∆1 , H, ν, µ), s′2 ) ⇒c (η2 , ∆2 , H2 , ν2 , µ2 ) then we must have that ∧

η1 = η2

ν1 = ν 2

∧

µ1 = µ 2

∆1 ⊆ ∆ 2 (P ′ , H2 , ∆2 ) ⋊ H1 Since we have η ′ = η1 , ∆′ = ∆1 , H ′ = H1 , ν ′ = ν1 , µ′ = µ1 , ∆ ⊆ ∆1 from before, then we can further simplify to obtain η ′ = η1 = η2

∧

ν ′ = ν1 = ν2

∧

µ′ = µ 1 = µ 2

∆ ⊆ ∆1 ⊆ ∆2 (P ′ , H2 , ∆2 ) ⋊ H1 Finally, executing concretely the third part of s′′ , we get Θ ⊢ ((η2 , ∆2 , H2 , ν2 , µ2 ), s3 ) ⇒c (η3 , ∆3 , H3 , ν3 , µ3 ) where s3 = addP uts(P ′ ), which is defined as addP uts(P ′ ) = put f ield(r1 , f1 , t1 ); . . . ; put f ield(rn , fn , tn )

∀((ri , fi ), ti ) ∈ P ′ , 1 ≤ i ≤ n, n = |P ′ |

Here we have that η ′′ = η3 , ∆′′ = ∆3 , H ′′ = H3 , ν ′′ = ν3 , µ′′ = µ3 . Notice that the addP uts(P ′ ) operation does not alter any of the environment variables except for the heap. Thus, we obtain η ′′ = η3 = η2 = η1 = η ′ , ν ′′ = ν3 = ν2 = ν1 = ν ′ , µ′′ = µ3 = µ2 = µ1 = µ′ (conclusion 1). Furthermore, we have ∆3 = ∆2 , where ∆′′ = ∆3 , ∆′ = ∆1 , and that ∆ ⊆ ∆1 ⊆ ∆2 , thus, we can conclude ∆′ = ∆2 ⊆ ∆3 = ∆′′ (conclusion 2). Finally, we have already established that (P ′ , H2 , ∆2 ) ⋊ H1 . By definition, this means that for any reference-field pair (ri , fi ) ∈ Dom(H1 ): if (ri , fi ) ∈ Dom(P ′ ), then its value is given by ∆2 (P ′ (ri , fi )), such that ∆2 (P ′ (ri , fi )) = H1 (ri , fi ); otherwise, we have H1 (ri , fi ) = H2 (ri , fi ). / Therefore, executing addP uts(P ′ ) in state s3 restores the values of all referencefield pairs in P ′ to the heap H3 . This must yield that H3 have all the mappings that were perviously in P ′ , thereby, we must have H 1 = H 3 , establishing conclusion (3). □

59

Finally, we can conclude that the following corollary holds:

Corollary 13.6. input and output are the same before and after rewriting ∀o ∈ O, ∆′′ (o) = ∆′′′ (o) Proof This follows directly from the application of the subset relation from Theorem 13.3, ∆′′ ⊆ ∆′′′ . And since the output variable names has not changed, then we must have that ∀o ∈ O, ∆′′ (o) = ∆′′′ (o). □

13.2 Properties of the Field Transformation The field transformation assumes all the guaranteed properties from pervious transformations: γ -creation, remove final-returns, renaming, method-inlining and substitution transformations. Given, ∆s , Hs ⊢ ((I, O, T ), s) −→f ield−wrap ((I, O, T ′ ), s′ ) The field transformation assumes the following property:

• Field-SSA Transformation maintains the SSA property (Property A.1). More formally, if ∆s , Hs ⊢ ((I, O, T ), s) −→f ield−wrap ((I, O, T ′ ), s′ ) s′ = addGets(P ); skip; s′′ ; skip; addP uts(P ′ ) SSA(s) then SSA(s′ ) Proof We know that the get − f ields introduced by the addGets(P ), creates new assignment statements of the form get f ield(P (r1 , f1 ), r1 , f1 ); . . . ; get f ield(P (rn , fn ), rn , fn ), ∀(ri , fi ) ∈ Dom(P ), 1 ≤ i ≤ n, n = |P |, where P = initialP (Hs ). Observe here that all reference-field pairs are mapped to fresh variable(s) ti , which by definition cannot clash with any of the existing variables. From lemma 13.3, we know that SSA(s′′ ). Finally, the last component of the rewritten statement, the addP uts(P ′ ), do not introduce new assignment statements. Thus, we can conclude that SSA(s′ ) holds. □

14 T R8 : Constant Reference Propagation The constant reference propagation transformation aims to resolve reference variables by propagating concrete references to subsequent variables in the IR. Fig. 15 shows the rules for the transformation. The rules define two judgments. The judgment T ⊢ (∆r , s) −→const ∆′r traverses an IR statement s, accumulating mappings from variables to their resolved concrete references in ∆r , where T is the set of temporary variables whose assignments to concrete references are eligible for collection. The wrapper judgment ∆s , T ⊢ ((µs , πr ), s) −→const-wrap ((πr′ , µ′s ), s′ ) is the entry point of the transformation, triggering the const judgment on s to collect ∆r , then applying 60

substitution via sub − wrap to replace all occurrences of the collected reference variables throughout s, πr , and µs , producing the rewritten statement s′ and updated πr′ and µ′s . resolved concrete references. Rule const-assign-change handles the core case: if a variable x ∈ T is assigned a concrete reference r ∈ R, then ∆r is updated to record this mapping. Rule const-assign-no-change handles the remaining assignment cases, where either x ∈ / T or the right-hand side is not a concrete reference, leaving ∆r unchanged. Rules const-if and const-comp propagate the transformation structurally, threading ∆r through sequential composition while processing both branches of a conditional independently. All other statements are handled by const-no-op, which leaves ∆r unchanged. Rule const-wrapper ties the transformation together. It first applies the constant propagation judgment to collect all concrete reference assignments into ∆r , effectively replacing those assignments with skip while recording their mappings. Once ∆r is fully populated, the wrapper immediately applies sub-wrap to substitute all occurrences of the collected reference variables throughout the IR with their corresponding concrete references in ∆r . This two-phase design ensures that all concrete references are first identified and collected in a single pass, and then propagated uniformly to all their use sites via substitution, resolving previously unresolved reference variables for subsequent transformations such as field elimination and method inlining. Next, rule const-assign-change handles the core case: if a variable x ∈ T is assigned a concrete reference r ∈ R, then ∆r is updated to record this mapping. Rule const-assign-no-change handles the remaining assignment cases, where either x ∈ / T or the right-hand side is not a concrete reference, leaving ∆r unchanged. Rules const-if and const-comp propagate the transformation structurally, threading ∆r through sequential composition while processing both branches of a conditional independently. All other statements are handled by const-no-op, which leaves ∆r unchanged. The resulting map ∆r is then used by the substitution transformation to replace unresolved reference variables with their concrete counterparts in subsequent transformations. Here the noOpconst (s) is defined as noOpconst (return e) = true noOpconst (skip) = true noOpconst (new(z, c)) = true noOpconst (put f ield(z, f, e)) = true noOpconst (get f ield(x, z, f )) = true − noOpconst (invoke(x, z, g, → y )) = true noOpconst (s) = f alse otherwise

noOpconst (e1 ⋄ e2 ) = true noOpconst ( e) = true noOpconst (γ (e1 , e2 , e3 )) = true noOpconst (e) = f alse otherwise

61

14.1 Constant Reference Propagation is Sound We now establish a key invariant of the constant propagation judgment: the reference map ∆r remains a subset of the concrete local variable mapping ∆ throughout the transformation. Intuitively, this ensures that every mapping collected in ∆r corresponds to a valid concrete reference assignment witnessed during execution, and that ∆r never introduces mappings that conflict with the symbolic state ∆s . Lemma 14.1 formalizes this: given that ∆r ⊆ ∆ holds before rewriting s, it is preserved after rewriting, i.e., ∆′r ⊆ ∆′ , and ∆r remains disjoint from ∆s .

Lemma 14.1. T ⊢ (∆r , s) −→const ∆′r Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) ∆r ⊆ ∆ then ∆′r ⊆ ∆′ Proof For assignment statements, two rewriting cases are distinguished: const-assign-change and const-assign-no-change. The former applies when the assigned expression evaluates to a concrete reference value and the target variable is a temporary variable; the latter applies otherwise. Let us consider the first case, i.e., const-assign-change, in this case the rewrite writes to T ⊢ (∆r , x := r) −→const ∆′r , such that x ∈ T, ∆′r = ∆r [x ← r]. Now, executing the original statement concretely we get Θ ⊢ ((η, ∆, H, ν, ⊥), x := r) ⇒c (η, ∆′ , H, ν, ⊥), such that ∆′ = ∆[x ← − r], ∆ ⊢ r ⇝c r. Since we have ∆r ⊆ ∆, and the only added mapping to both ∆′ and ∆′r is the mapping for x, i.e., ∆[x ← − r], then we can conclude that ∆′r ⊆ ∆′ Next consider const-no-change rule. In this case, no change occurs on ∆r ; i.e., ∆′r = ∆r . Also, we have from the premise of the lemma that ∆r ⊆ ∆. Since, ∆′ is exactly as ∆ with an additional mapping for x, then it must be that ∆r = ∆′r ⊆ ∆′ . Also, a similar argument is used for the proof of const-no-op rule. Next, consider const-if rule. In this case, the rewrite writes to T ⊢ (∆r , if e then s1 else s2 ) −→const ∆r , such that T ⊢ (∆r , s1 ) −→const ∆′r and T ⊢ (∆r , s2 ) −→const ∆′′ r . There are two cases when executing this statement concretely depending on whether the evaluation for e evaluates to true or f alse. We will show the proof for the first case, but the second case is very similar. Here we have ∆ ⊢ e ⇝c true, which implies that if-phi-true must apply. Thus, we will have ((η, ∆, H, ν, µ), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , µ1 ), here we have that ∆′ = ∆1 . Recall from Lemma 4.2, it must be that ∆ ⊆ ∆1 . Since we have from the statement of the lemma that ∆r ⊆ ∆, then by transitivity, we have that ∆r ⊆ ∆1 = ∆′ , which is what we want to prove. Finally, consider const-comp rule. In this case, we have that T ⊢ (∆r , s1 ; s2 ) −→const ∆r2 , such that T ⊢ (∆r , s1 ) −→const ∆′r1 , and T ⊢ (∆′r1 , s2 ) −→const ∆r2 . Here we have that ∆′r = ∆r2 . Observe here that const-comp only applies after removing final return transformation (Property A.16). Thus, the only concrete compositional rule that can apply at this point is composition. Here, we get Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ; s2 ) ⇒c (η2 , ∆2 , H2 , ν2 , µ2 ), where Θ ⊢ ((η, ∆, H, ⊥), s1 ) ⇒c (η1 , ∆1 , H1 , ν1 , ⊥), and Θ ⊢ ((η1 , ∆1 , H1 , ν1 , ⊥), s2 ) ⇒c (η2 , ∆2 , H2 , ν2 , µ2 ). Here we have ∆2 = ∆′ . By induction on s1 , we get ∆r1 ⊆ ∆1 , which allows us to use the lemma over s2 to obtain ∆′r = ∆r2 ⊆ ∆2 = ∆′ , which is what we want to prove. □

62

Building on Lemma 14.1, we now lift the soundness result to the wrapper judgment. Lemma 14.2 establishes that executing the original statement s and its rewritten counterpart s′ from the same concrete state produce the same observable behavior: the same control state η , heap H , path condition ν , and return value µ. Furthermore, the local variable mapping is extended consistently, i.e., ∆′ ⊆ ∆′′ , the concrete state remains a model of the symbolic state after rewriting, and the return semantics captured by πr′ and µ′s faithfully reflect the original return behavior, i.e., evalReturn(∆′ , πr , µs ) = evalReturn(∆′′ , πr′ , µ′s ).

Lemma 14.2. (∆) |= (∆s , π ) ∆s , T ⊢ ((µs , πr ), s) −→const−wrap ((µ′s , πr′ ), s′ ) Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

µ∗ = evalReturn(∆′ , πr , µs ) Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ) then ∆′ ⊆ ∆′′

η ′′ = η ′ , H ′′ = H ′ , ν ′′ = ν ′ , µ′′ = µ′ µ∗ = evalReturn(∆′′ , πr′ , µ′s ) Proof Here, we have that T ⊢ s −→const−wrap ∆r , such that T ⊢ (∅, s) −→const ∆r , I ′ = Dom(∆r ) and ∆s ∪ ∆r ⊢ ((πr , µs , I ′ ), s) −→sub−wrap ((πr′ , µ′s , I ′′ ), s′ ). In this case, we obviously have ∅ ⊆ ∆. Thus, we can apply the const-statement lemma 14.1 to conclude that ∆r ⊆ ∆′ . Now, we want to apply Corollary 11.3, to show that apply substitution on the collected references is sound. Let ∆′s = ∆s ∪ ∆r . First, we show that the premises of Corollary 11.3 hold, then we apply it. Observe that

• We want to show that ∀i ∈ I.∀x ∈ Dom(∆′s ).¬isU se(i, ∆′s (x)). Since ∆′s = ∆s ∪ ∆r , then we want to show that this condition holds for both ∆r and ∆s . To see how it holds for ∆r , observe that I ′ = Dom(∆r ) and that ∆r only collects assignments from constants, then it must be that the Range(∆r ) ∈ V , i.e., all mapped to expressions, must be concrete values, which means there cannot be any usage of any variable in the Range(∆r ), which makes this condition holds for ∆r . To see why it holds for ∆s , since SSA(s) (guaranteed property from field transformation, i.e., Property A.1) and the definitions of I ′ comes from within s, then that means there cannot be any uses of it within Range(∆s ), thus here too, the condition holds. • since we have that (∆) |= (∆s , π ) holds from the premise of the current lemma. And again because of the SSA property for s we know that ∆r ∩ ∆s = ∅, thus evaluating expression in ∆s ∪ ∆r must yield the same values, thus we can conclude that (∆) |= (∆s ∪ ∆r , π ); i.e., (∆) |= (∆′s , π ). • finally, we have that ∆ ⊆ ∆. The above allows us to apply Corollary 11.3, to conclude that ∆′ ⊆ ∆′′ , η ′′ = η ′ , H ′′ = H ′ , ν ′′ = ν ′ , µ′′ = µ′ , (∆′′ ) |= (∆s , π), µ∗ = evalReturn(∆′′ , πr′ , µ′s ), and that ∀i ∈ I ′ .¬isU se(i, s′ ). □

63

14.2 Properties of Constant Reference Propagation The transformation assumes all properties guaranteed by previous transformations, i.e., γ-creation, remove final-returns, renaming, method-inlining and field-SSA transformations. In addition the constant reference propagation transformation guarantees the following property • Rewritten Statement s′ satisfies the generalized SSA property (Property A.1). More formally, SSA(s′ ) holds.

15 Path-Merging Fix-Point Algorithm Algorithm 2: JR Static-Summary-Instantiation Algorithm Input: to-summarize statement s Input: concrete state δ = (Θ, η, ∆, H, ν, µ)) 3 Data: Ranger State ω = (Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I, O, T ), u) 4 ω :=initialize-state(δ ) where ω = (Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I, O, T ), u) 1 5 s −→γ−wrap s 1 2 2 6 s →ret−wrap (πr , s ) 2 7 s −→f inal−wrap (µ3s , s3 ) 3 2 3 4 4 4 4 4 8 I, O ⊢ ((µs , πr , T, u), s ) −→rename−wrap ((T , µs , πr , u ), s ) 4 4 4 5 5 5 5 9 ∆s ⊢ (πr , µs , I, s ) −→sub−wrap ((πr , µs , I ), s ) ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ 10 (Θt , ηs , ∆s , Hs , µs , (π , πr , πs ) , (I , O , T ), u ) := 5 5 5 4 ((Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I , O, T ), u4 ), s5 ) ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ ′ 5 11 (ω , s ) := ((Θt , ηs , ∆s , Hs , µs , (π , πr , πs ) , (I , O , T ), u ), s ) 12 repeat 13 (ωf ix , sf ix ) := (ω ′ , s′ ) 14 Θ′t , ηs′ , ∆′s ⊢ ((T ′ , u′ ), s′ ) −→inline−wrap ((T 6 , u6 ), s6 ) 15 ∆′s , Hs′ ⊢ ((I ′ , O′ , T 6 ), s6 ) −→f ield−wrap ((I ′ , O′ , T 7 ), s7 ) 16 ∆′s , T 7 ⊢ ((µ′s , πr′ ), s7 ) −→const−wrap ((πr8 , µ8s , ), s8 ) 17 (ω ′ , s′ ) := ((Θ′t , ηs′ , ∆′s ∪ ∆r , Hs′ , µ8s , (π, πr8 , πs8 ), (I ′ , O′ , T 7 ), u8 ), s8 ) ′ ′ 18 until (ωf ix , sf ix ) := (ω , s ) 19 return (ωf ix , sf ix ) 1 2

15.1 Path-Merging fix-point Algorithm is Sound We divide the proof of the path-merging Algorithm into three main parts. First, we show that the transformations before hitting the fix-point loop are sound, i.e., line 5-9. Then, we show that the fix-point loop is terminating and sound (line 12-16).

64

Before we show the proof, we define T Ri to denote the a particular transformation, more formally:

T R1 (ω, s) = (ω, s′ ),

where s −→γ-wrap s′

T R2 (ω, s) = (ω ′ , s′ ), where s →ret-wrap (πr′ , s′ ), ω ′ = ω [πr′ /πr ] T R3 (ω, s) = (ω ′ , s′ ), where s −→f inal-wrap (µ′s , s′ ), ω ′ = ω [µ′s /µs ] T R4 (ω, s) = (ω ′ , s′ ), where I, O ⊢ ((µs , πr , T, u), s) −→rename-wrap ((T ′ , µ′s , πr′ , u′ ), s′ ), ω ′ = ω [µ′s /µs , πr′ /πr , T ′ /T, u′ /u] T R5 (ω, s) = (ω ′ , s′ ), where ∆s ⊢ (πr , µs , I, s) −→sub-wrap ((πr′ , µ′s , I ′ ), s′ ), ω ′ = ω [πr′ /πr , µ′s /µs , I ′ /I ] T R6 (ω, s) = (ω ′ , s′ ), where Θt , ηs , ∆s ⊢ ((T, u), s) −→inline-wrap ((T ′ , u′ ), s′ ), ω ′ = ω [πr′ /πr , T ′ /T, u′ /u] T R7 (ω, s) = (ω ′ , s′ ), where ∆s , Hs ⊢ ((I, O, T ), s) −→f ield-wrap ((I ′ , O′ , T ′ ), s′ ), ω ′ = ω [I ′ /I, O′ /O, T ′ /T ] T R8 (ω, s) = (ω ′ , s′ ), where T ⊢ ((µs , πr ), s′ ) −→const-wrap ((πr′ , µ′s ), s′ ), ω ′ = ω [(πr′ /πr , µ′s /µs ] We use the notation T Rn to denote the application of a set of transformations, such that

T Rn (ω, s) = (ω ′ , s′ ), where (ω ′ , s′ ) = T Rn ◦ T Rn−1 ◦ · · · ◦ T R1 (ω, s) Lemma 15.1. Pre-Fixed-Point Transformations (line 5-9) are Sound. Given a statement to path-merge s, a concrete state δ and a symbolic state ω , such that: Let δ = (η, ∆, H, ν, µ), δ ′ = (η ′ , ∆′ , H ′ , ν ′ , µ′ ), and δ ′′ = (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ). Let ω = (Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I, O, T ), u) = initialize-state(δ ) ω ′ = (Θ′t , ηs′ , ∆′s , Hs′ , µ′s , (π ′ , πr′ , πs′ ), (I ′ , O′ , T ′ ), u′ ). we have that Θ ⊢ (δ, s) ⇒c δ ′ ′

′

(ω , s ) = T R5 ◦ T R4 ◦ T R3 ◦ T R2 ◦ T R1 (ω, s) (∆) |= (∆s , π ) (∆, H ) |=H (∆s , Hs , π ) ∀i ∈ getInputs(s).∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) ηs ⊆ η Θ ⊢ (δ, s′ ) ⇒c δ ′′

65

(premise 1) (premise 2) (premise 3) (premise 4) (premise 5) (premise 6) (premise 7)

then

η ′ = η ′′ ∧ H ′ = H ′′ ∧ ν ′ = ν ′′ ∀i ∈ I ′ .∆′ (i) = ∆′′ (i) ∀o ∈ O′ .∆′ (o) = ∆′′ (o) µ′′ = ⊥ ′ µ = evalReturn(∆′′ , πr′ , µ′s ) (∆′′ ) |= (∆′s , π ′ ) ηs′ ⊆ η ′′ (∆, H ) |=H (∆′s , Hs′ , π ′ )

(conclusion 1) (conclusion 2) (conclusion 3) (conclusion 4) (conclusion 5) (conclusion 6) (conclusion 7) (conclusion 8)

Proof Observe that path-merge5−9 means executing the following transformations: s −→γ−wrap s1 s1 →ret−wrap (πr2 , s2 ) s2 −→f inal−wrap (µ3s , s3 ) I, O ⊢ ((µ3s , πr2 , T, u), s3 ) −→rename−wrap ((T 4 , µ4s , πr4 , u4 ), s4 ) ∆s ⊢ (πr4 , µ4s , I, s4 ) −→sub−wrap ((πr5 , µ5s , I 5 ), s5 ) where s′ = s5 , πr′ = πr5 , µ′s = µ5s , I ′ = I 5 , u′ = u4 , T ′ = T 4 and the other environment variables of the symbolic state remains unchanged, i.e., Θ′t = Θt , ηs′ = ηs , ∆′s = ∆s , Hs = Hs′ , πs′ = πs , O′ = O. First, observe that premise 3, 4, 5 and 6 satisfy the Property A.9, A.10, A.11 and A.7, respectively. Also, observe initialize-state(δ) also assumes that µ = ⊥ (Property A.6). Recall that transformations T R1 , T R2 and T R3 corresponds to the static transformations of Java Ranger, which we considered their composition in Theorem B.1, such that if Θ ⊢ ((η, ∆, H, ν, µ), s3 ) ⇒c (η 3 , ∆3 , H 3 , ν 3 , µ3 ) then η ′ = η 3 , ∆′ = ∆ 3 , H ′ = H 3 , ν ′ = ν 3 µ′ = evalReturn(∆3 , πr2 , µ3s ) µ3 = ⊥ Next, since we have that Θ ⊢ ((η, ∆, H, ν, µ), s3 ) ⇒c (η 3 , ∆3 , H 3 , ν 3 , µ3 ) µ = µ3 = ⊥ I, O ⊢ ((µ3s , πr2 , T, u), s3 )

−→rename−wrap ((T 4 , µ4s , πr4 , u4 ), s4 )

Θ ⊢ ((η, ∆, H, ν, µ), s4 ) ⇒c (η 4 , ∆4 , H 4 , ν 4 , µ4 )

66

then, we can apply renaming theorem (knowing that we have shown that ∆′ = ∆3 from before) (Theorem 10.3) to get ∀i ∈ I, ∆(i) = ∆3 (i) = ∆4 (i) = ∆′ (i) ∀o ∈ O, ∆3 (o) = ∆4 (o) = ∆′ (o) evalReturn(∆3 , πr2 , µ3s ) = evalReturn(∆4 , πr4 , µ4s ) where η = η = η ′ , H 4 = H 3 = H ′ , ν 4 = ν 3 = ν ′ = ⊥, µ4 = µ3 = ⊥. Also, observe that we have established from before that µ′ = evalReturn(∆3 , πr2 , µ3s ), and we also have shown that 4

3

evalReturn(∆3 , πr2 , µ3s ) = evalReturn(∆4 , πr4 , µ4s ) thus by transitivity, we have µ′ = evalReturn(∆4 , πr4 , µ4s ) Next, consider the sub-wrap. From premise 4, 5 of the lemma, we have that (∆) |= (∆s , π) ∀i ∈ I.∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) then if ((πr4 , µ4s , I), s4 ) −→sub−wrap ((πr5 , µ5s , I 5 ), s5 ) Θ ⊢ ((η, ∆, H, ν, µ), s5 ) ⇒c (η 5 , ∆5 , H 5 , ν 5 , µ5 ) Then, we can apply Corollary 11.3, reusing ∆ in the position of the free local variable mapping (named ∆′′ in Corollary 11.3). Since ∆ ⊆ ∆, we get η 5 = η 4 , H 5 = H 4 , ν 5 = ν 4 , µ5 = µ 4 ∆4 ⊆ ∆ 5 ∀i ∈ I.¬isU se(i, s5 ) (∆5 ) |= (∆s , π 5 ) evalReturn(∆4 , πr4 , µ4s ) = evalReturn(∆5 , πr5 , µ5s ) Observe that since this is the last transformation in path-merge5−9 , then we have η ′′ = η 5 , ∆′′ = ∆5 , H ′′ = H 5 , ν ′′ = ν 5 . and by transitivity, we get η ′′ = η 5 = η 4 = η ′ , H ′′ = H 5 = H 4 = H ′ , ν ′′ = ν 5 = ν 4 = ν ′ (conclusion 1). Here, we know that the set of inputs I and set of outputs O are unchanged by any of the transformation, and also must have mappings in ∆4 . Now, as ∆4 ⊆ ∆5 , then we know that all mapping for variables in I and O must be exactly the same between ∆4 and ∆5 . Therefore we can conclude that ∀i ∈ I, ∆4 (i) = ∆5 (i) = ∆′′ (i) ∀o ∈ O, ∆4 (o) = ∆5 (o) = ∆′′ (o) since we have shown that ∆3 = ∆′ , by transitivity we can conclude that ∀i ∈ I, ∆′ (i) = ∆′′ (i), and similarly, we conclude that ∀o ∈ O, ∆′ (o) = ∆′′ (o). And since none of the transformations changed the input or the output, then we can conclude that the new input I ′ and output O′ must have ∀i ∈ I ′ , ∆′ (i) = ∆′′ (i) (conclusion 2), and that, ∀o ∈ O′ , ∆′ (o) = ∆′′ (o) (conclusion 3). Also, we have that µ′′ = µ4 = ⊥ (conclusion 4). Note that here πr′ = πr4 , µ′s = µ4s . Finally, by transitivity we have that evalReturn(∆5 , πr5 , µ5s ) = evalReturn(∆4 , πr4 , µ4s ) = evalReturn(∆3 , πr2 , µ3s ) = µ′ (conclusion 5)

67

We also observe that the symbolic variable mapping ∆s , and reference mappings remain unchanged, i.e., ∆′s = ∆s , ηs′ = η. And we concluded from applying Corollary 11.3 that (∆5 ) |= (∆′s , π)

(conclusion 6)

′′

Also, as shown above, η = η, and ηs ⊆ η from premise 7, thus ηs′ ⊆ η ′′ (conclusion 8). Finally, since we have ∆′s = ∆s , Hs′ = Hs and π ′ = π, and from premise 4, we can conclude that we have (∆, H) |=H (∆′s , Hs′ , π ′ ) (conclusion 8) established. □

Lemma 15.2. Applying transformations from line 14-16 is sound. Given a statement to path-merge s, a concrete state δ and a symbolic state ω , such that:

• δ = (η, ∆, H, ν, µ) • δ ′ = (η ′ , ∆′ , H ′ , ν ′ , µ′ ) • δ ′′ = (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ) • ω = (Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I, O, T ), u) • ω ′ = (Θ′t , ηs′ , ∆′s , Hs′ , µ′s , (π ′ , πr′ , πs′ ), (I ′ , O′ , T ′ ), u′ ). we have that Θ ⊢ (δ, s) ⇒c δ ′

(premise 1)

(ω , s ) = T R8 ◦ T R7 ◦ T R6 (ω, s)

(premise 2)

(∆) |= (∆s , π )

(premise 3)

′

′

∀i ∈ getInputs(s).∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) Θ ⊢ (δ, s′ ) ⇒c δ ′′ ηs ⊆ η

(premise 4) (premise 5) (premise 6)

then

η ′ = η ′′ ∧ H ′ = H ′′ ∧ ν ′ = ν ′′ ∀i ∈ I ′ .∆′ (i) = ∆′′ (i) ∀o ∈ O′ .∆′ (o) = ∆′′ (o) µ′′ = ⊥ µ′ = evalReturn(∆′′ , πr′ , µ′s ) ∀i ∈ I ′ .¬isU se(i, s′ ) (∆′′ ) |= (∆′s , π ′ ) ηs′ ⊆ η ′′

68

(conclusion 1) (conclusion 2) (conclusion 3) (conclusion 4) (conclusion 5) (conclusion 6) (conclusion 7) (conclusion 8)

15.2 Loop Invariant We will define the loop invariant to be a property of the state of the rewriting (ω i , si ), that says, that if we are in the middle of the writing, such that (ω i , si ) is the current rewriting state, then that rewriting is preserving the semantics of the original code, i.e., concretely executing the currently rewritten statement is sound with respect to executing the original statement concretely. We use the superscript i notation to suggest that the loop invariant will hold after i iterations of the fix point loop, in a way that we will define later. More formally, we define the loop invariant be a predicate on the state of the rewriting (ω i , si ), parameterized by the initial concrete state δ , initial symbolic state ω and the original statement s. We further define:

• we write the components of the original concrete state δ as (η, ∆, H, ν, µ). • state after evaluating the original statement: δ ⊥ = (η ⊥ , ∆⊥ , H ⊥ , ν ⊥ , µ⊥ ), defined by Θ ⊢ (δ, s) ⇒c δ ⊥ . • state after evaluating the rewritten statement after executing the fix-loop i times: δ i = (η i , ∆i , H i , ν i , µi ), defined by Θ ⊢ (δ, si ) ⇒c δ i . • initial state before any rewriting ω = (Θt , ηs , ∆s , Hs , µs , (π, πr , πs ), (I, O, T ), u). • state of the rewriting statement after executing the fix-loop ith times: ω i = (Θit , ηsi , ∆is , Hsi , µis , (π i , πri , πsi ), (I i , Oi , T i ), ui ). The loop invariant is the conjunction of the following properties:

ηi = η⊥ ∧ H i = H ⊥ ∧ ν i = ν ⊥ i

⊥

i

∀o ∈ O .∆ (o) = ∆ (o) i

µ =⊥ ⊥

µ

(invariant 1) (invariant 2) (invariant 3)

i

= evalReturn(∆ , πri , µis ) ∆ |= (∆is , π i ) (∆, H ) |=H (∆is , Hsi , π i ) ηsi ⊆ η i

(invariant 4) (invariant 5) (invariant 6) (invariant 7)

We prove that the invariant holds at the entry of the fixpoint loop, i.e., before the first iteration. We use superscript 0 to denote the state upon first entering the loop, and superscript i to denote the state after i iterations. The invariant is first established at line 13, which marks the beginning of the loop body, and we show that it holds at this point before any iteration has been executed, i.e., at superscript 0. Proof We establish the correctness of the loop invariant by induction. Base Case: Initially, before any rewriting happens, as per Algorithm 1, we have the

following assumptions between the concrete state and the symbolic state: Assumption Property A.7: ηs ⊆ η 69

– Assumption Property A.9: ∆ |= (∆s , π ) – Assumption Property A.6: µ = µs = ⊥ – Assumption Property A.11: ∀i ∈ getInputs(s).∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) From Properties A.9, A.11, and A.7, we apply Lemma 15.1 to establish the soundness of the pre-fixpoint transformations T R1 –T R5 , where (ω 0 , s0 ) = T R5 ◦ T R4 ◦ T R3 ◦ T R2 ◦ T R1 (ω, s), such that Θ ⊢ (δ, s) ⇒c δ ⊥ Θ ⊢ (δ, s0 ) ⇒c δ 0 (ω, s) −→T R (ω 0 , s0 ) Thus, here we get:

η0 = η⊥ ∧ H 0 = H ⊥ ∧ ν 0 = ν ⊥ ∀o ∈ O0 .∆⊥ (o) = ∆0 (o) µ0 = ⊥ µ⊥ = evalReturn(∆0 , πr0 , µ0s ) (∆⊥ , H ⊥ ) |=H (∆0s , Hs0 , π 0 ) (∆) |= (∆0s , π 0 )

ηs0 ⊆ η 0 which directly satisfies the loop invariant just before entering the loop. Inductive Case: From the induction hypothesis we know that the loop invariant hold at iteration i − 1. Now, assuming rewriting has finished ith iteration within the loop. Thus, we will have (ω i−1 , si−1 ) −→T R6−8 (ω i , si ) Θ ⊢ (δ, si−1 ) ⇒c δ i−1 Θ ⊢ (δ, si ) ⇒c δ i more precisely, we know that η i−1 = η ⊥ ∧ H i−1 = H ⊥ ∧ ν i−1 = ν ⊥ ∀o ∈ O

i−1

.∆

µ µ

⊥

i−1

i−1

⊥

(induction 1)

(o) = ∆ (o)

(induction 2)

=⊥

(induction 3)

i−1

(induction 4)

= evalReturn(∆

, πri−1 , µi−1 s ) i−1

∆ |= (∆i−1 ) s ,π i−1 i−1 i−1 (∆, H) |=H (∆s , Hs , π ) i−1 i−1 ηs ⊆ η

(induction 5) (induction 6) (induction 7)

Now we divide the prove induction into three main steps, each of them talking about on of the transformations from lines 14-16 in Algorithm 2, and proving that the invariant holds after each transformation.

70

The first transformation within the loop is the method inlining. To use its soundness lemma (Lemma 12.4) we know to satisfy its premise, more precisely, we need to show that, given an intermediate concrete and symbolic state after executing the method-inlining as Θ ⊢ ((η, ∆, H, ν, µ), si−1 ) ⇒c (η i−1 , ∆i−1 , H i−1 ν i−1 , µi−1 ) Θi−1 , ηsi−1 , ∆i−1 ⊢ ((T i−1 , ui−1 ), si−1 ) −→inline−wrap ((Tin , uin ), sin ) s t Θ ⊢ ((η, ∆, H, ν, µ), sin ) ⇒c (ηin , ∆in , Hin , νin , µin ) the premise of the inlining wrap lemma (Lemma 12.4) below i−1 (∆) |= (∆i−1 ) s ,π

(from induction 5)

ηsi−1 ⊆ η i−1

(from induction 7)

We can now apply Lemma 12.4 for soundness of the inlining wrapper to get the following. ∆i−1 ⊆ ∆in ηin = η

i−1

, Hin = H

(inline 1) i−1

, νin = ν

i−1

, µin = µ

i−1

(inline 2)

ηsi−1 ⊆ ηin

(inline 3)

i−1 i−1 evalReturn(∆i−1 , πri−1 , µi−1 s ) = evalReturn(∆in , πr , µs ) i−1 (∆in ) |= (∆i−1 ) s ,π

(inline 4) (inline 5)

Observe that in the inlining transformation, the only two environment variables that are changing is T and u (from T i−1 and ui−1 to Tin and uin ), the other environment variables stays the same as those in iteration i − 1. That is i−1 , µsin = µi−1 Θtin = Θi−1 , ηsin = ηsi−1 , ∆sin = ∆i−1 s s , Hsin = Hs t

πin = π i−1 , πrin = πri−1 , πsin = πsi−1 , Iin = I i−1 , Oin = Oi−1

(inline 6)

The inlining transformation preserves the loop invariant. - Inline invariant 1 (ηin = η ⊥ ∧ Hin = H ⊥ ∧ νin = ν ⊥ ) follows by combining (inline 2), which gives ηin = η i−1 , Hin = H i−1 , νin = ν i−1 , with (induction 1), which gives η i−1 = η ⊥ , H i−1 = H ⊥ , ν i−1 = ν ⊥ , and applying transitivity. -Inline Invariant 2 (∀o ∈ Oin . ∆in (o) = ∆⊥ (o)) follows by combining (inline 1), which gives ∆i−1 ⊆ ∆in , with the observation that Oin = Oi−1 , ensuring that all output mappings are preserved in ∆in . Applying (induction 2) transitively then establishes that every output variable in Oin carries the same mapping as in ∆⊥ . - Inline invariant 3 (µin = ⊥) can be easily established from inline 6, which states that i−1 µsin = µi−1 = ⊥), to conclude that s , then we can use transitivity from induction 3 (µ inline invariant 3 (µin = ⊥) holds after the method inlining transformation. - Inline Invariant 4 (µ⊥ = evalReturn(∆in , πrin , µsin )) follows directly by transitivity from i−1 i−1 (inline 4), which gives evalReturn(∆i−1 , πri−1 , µi−1 s ) = evalReturn(∆in , πr , µs ), and (induction 4), which gives µ⊥ = evalReturn(∆i−1 , πri−1 , µi−1 ). s - Inline Invariant 5 (∆ |= (∆sin , πin )) holds because none of the symbolic states need in this function has changed. More precisely, (inline 6) gives ∆sin = ∆i−1 and Hsin = Hsi−1 , s i−1 i−1 and applying transitivity over (induction 5), which gives ∆ |= (∆s , π ), establishes the invariant.

71

- Inline Invariant 6 ((∆, H) |=H (∆sin , Hsin , πin )) holds again since none of the symbolic states needed in this function has changed. More precisely (inline-6) gives ∆sin = i−1 ∆i−1 , πin = π i−1 , then applying transitivity over (induction 6) which gives s , Hsin = Hs i−1 (∆, H) |=H (∆s , Hsi−1 , π i−1 ), we establish the invariant. - Finally, Inline Invariant 7 (ηsin ⊆ ηin ) directly holds from inline 3 which states that ηsi−1 ⊆ ηin , as well as inline 6 (ηsin = ηsi−1 ). Thus, we have established that the method-inlining preserves the loop invariant. More specifically, ηin = η ⊥ ∧ Hin = H ⊥ ∧ νin = ν ⊥

(inline-inv 1: from inline 2, induction 1)

⊥

∀o ∈ Oin .∆in (o) = ∆ (o)

(inline-inv 2: from inline 1, induction 2)

µin = ⊥

(inline-inv 3: from inline 2, induction 3)

µ⊥ = evalReturn(∆in , πrin , µsin )

(inline-inv 4: from inline 4, induction 4)

∆ |= (∆sin , πin )

(inline-inv 5: from inline 6, induction 5)

(∆, H) |=H (∆sin , Hsin , πin )

(inline-inv 6: from inline 6, induction 6)

ηsin ⊆ ηin

(inline-inv 7: from inline 3 and 6)

The next transformation is the one at line 15, the field SSA transformation. Here, we apply Lemma 13.5, this is because from (inline 6) we have satisfied the first premise for Lemma 13.5 and we know that the field transformation rewriting will produce: i−1 ∆i−1 ⊢ ((I i−1 , Oi−1 , Tin ), sin ) −→f ield−wrap ((I i−1 , Oi−1 , Tf ield ), sf ield ) s , Hs

Finally, executing concretely the field-transformed statement, we get: Θ ⊢ ((η, ∆, H, ν, µ), sf ield ) ⇒c (ηf ield , ∆f ield , Hf ield , νf ield , µf ield ) Given the above, we applying Lemma 13.5 to obtain ηf ield = ηin

∧

νf ield = νin

∧

µf ield = µin

(field 1)

∆in ⊆ ∆f ield

(field 2)

Hf ield = Hin

(field 3)

From here we can see that the field transformation is preserving the loop invariant, for similar reasoning that we have established before when presenting the proof that the method inlining preserves the loop invariant. More precisely. we have that invariant 1 satisfied by transitivity from field 1 and field 3. Invariant 2 is satisfied from field 2, i.e., output variables are still the same when comparing them after executing the non-rewritten statement, versus the field rewritten statement. Invariant 3, 4, 5, 6 and 7 are all satisfied since none of these symbolic states have changed by field SSA transformation, i.e., Θtf ield = Θtin , ηsf ield = ηsin , ∆sf ield = ∆sin , Hsf ield = Hsin , µsf ield = µsin , πf ield = πin πrf ield = πrin , πsf ield = πsin , If ield = Iin , Of iled = Oin , uf ield = uin

(field 4)

then we can conclude by transitivity from the previous transformation, that the field transformation also preserves invariants 3-7.

72

More precisely, we have ηf ield = η ⊥ ∧ Hf ield = H ⊥ ∧ νf ield = ν ⊥

(field-inv 1: from field 1, 3, inline-inv 1)

⊥

∀o ∈ Of ield .∆f ield (o) = ∆ (o)

(field-inv 2: from field 2, inline-inv 2)

µf ield = ⊥

(field-inv 3: from field 1, inline-inv 3)

µ⊥ = evalReturn(∆f ield , πrf ield , µsf ield )

(field-inv 4: from field 1, 2, 4, inline-inv 4)

∆ |= (∆sf ield , πf ield )

(field-inv 5: from field 4, inline-inv 5)

(∆, H) |=H (∆sf ield , Hsf ield , πf ield )

(field-inv 6: from field 4, inline-inv 6)

ηsf ield ⊆ ηf ield

(field-inv 7: from field 1, inline-inv 7)

Next, we want to apply the reference constant propagation transformation. We have already proven that the field transformation maintains invariant 5 (field-inv 5), that is ∆ |= (∆sf ield , πf ield ) and given a constant propagation rewriting and the execution of the its rewritten statement, such that we have ∆sf ield , Tf ield ⊢ ((µsf ield , πrf ield ), sf ield ) −→const−wrap ((µsconst , πrconst ), s) Θ ⊢ ((η, ∆, H, ν, µ), sconst ) ⇒c (ηconst , ∆const , Hconst , νconst , µconst ) µ∗ = evalReturn(∆const , πrf ield , µsf ield ) Now, applying the constant propagation lemma 14.2, we get ∆f ield ⊆ ∆const ηconst = ηf ield , Hconst = Hf ield , νconst = νf ield , µconst = µf ield µ∗ = evalReturn(∆const , πrconst , µsconst )

(const 1) (const 2) (const 3)

Observe here that, except from πrconst , µsconst , none of the symbolic environment variables have changed from the constant propagation rewriting, more precisely, we have that Θtconst = Θtf ield , ηsconst = ηsf ield , ∆sconst = ∆sf ield , Hsconst = Hsf ield µsconst = µsf ield , πconst = πf ield , πrconst = πrf ield , πsconst = πsf ield Iconst = If ield , Of iled = Of ield , Tconst = Tf ield , uconst = uf ield

(const 4)

Now, we can prove that the loop invariant hold from: ηconst = η ⊥ ∧ Hconst = H ⊥ ∧ νconst = ν ⊥ ⊥

µ

⊥

(const-inv 1: from const 1, field-inv 1)

∀o ∈ Oconst .∆const (o) = ∆ (o)

(const-inv 2: from const 4, field-inv 2)

µconst = ⊥

(const-inv 3: from const 2, field-inv 3)

= evalReturn(∆const , πrconst , µsconst )

(const-inv 4: from const 3, field-inv 4)

∆ |= (∆sconst , πconst )

(const-inv 5: from const 1, 4, field-inv 5)

(∆, H) |=H (∆sconst , Hsconst , πconst )

(const-inv 6: from const 1, 4, field-inv 6)

ηsconst ⊆ ηconst

(const-inv 7: from const 2, field-inv 7)

73

Observe here that this is the last transformation within the loop, thus we know that that η i = ηconst , ∆i = ∆const , H i = Hconst , ν i = νconst , µi = µconst . Similarly, we have Θit = Θconst , ηsi = ηsconst , ∆is = ∆sconst , Hsi = Hsconst , µis = µsconst , π i = πconst , πri = πrconst , πsi = πsconst , I i = Iconst , Oi = Oconst , T i = Tconst , ui = uconst . This means that we have just proved the loop invariant after iteration i. □

15.3 Conclusion In this paper, we presented the first formal treatment of path-merging symbolic execution, targeting Java Ranger as a representative tool. We formalized each of its code transformations and proved their soundness with respect to a simplified version of the Java concrete semantics, establishing that the path-merging process preserves program semantics. We hope this work lays the groundwork for future efforts toward formally verifying the correctness of symbolic execution tools more broadly, enforcing rigorous soundness guarantees for tools that are increasingly trusted in safety-critical verification contexts.

Appendix A

Properties

Here, we list properties that are shared among semantics.

Property A.1. For a statement s to be processed by Java Ranger, we assume that the statement obeys the Single Static Assignment property (SSA) for all local variable mappings; i.e., SSA(s), such that the SSA predicate is recursively defined as SSA(s1 ; s2 ) = ASSN (s1 ) ∩ ASSN (s2 ) = ∅ ∧ SSA(s1 ) ∧ SSA(s2 ) SSA(if e then s1 else s2 ; ϕ1 (x1 , e11 , e21 ); · · · ; ϕ(xn , e1n ; e2n )) = (ASSN (s1 ) ∪ ASSN (s2 )) ∩ {x1 , · · · , x2 } = ∅ ∧ SSA(s1 ) ∧ SSA(s2 ) SSA(s) = ⊤ otherwise where the ASSN function returns the set of all assigned to variables. Observe that this extends to implicit assignments from the invoke, getfield and new statements that collects the returned value. ASSN (x := e) = {x} ASSN (s1 ; s2 ) = ASSN (s1 ) ∪ ASSN (s2 ) ASSN (skip) = ∅ ASSN (if e then s1 else s2 ; ϕ1 (x1 , e11 , e21 ); · · · ; ϕ(xn , e1n ; e2n )) = ASSN (s1 ) ∪ ASSN (s2 ) ∪ {x1 , · · · , xn } → − ASSN (invoke(x, z, g, e ))) = {x} ASSN (return e) = ∅ 74

ASSN (put f ield(z, f, e)) = ∅ ASSN (new(z, c)) = {z} ASSN (get f ield(x, z, f )) = {x}

Property A.2 (Statement s always has at most a single return within an if-statement). , i.e., atMostSingleIfReturn(s). Let us define the function atM ostSingleIf Return such that atMostSingleIfReturn(s) = ¬hasReturn(s) ∨ singleIfReturn(s) where singleIfReturn and hasReturn are defined to capture the case where the statement s has at most a single return or none at all (see technical report for complete detail [33]) singleIfReturn(s1 ; s2 ) = ¬hasReturn(s1 ) ∧ singleIfReturn(s2 ) singleIfReturn(if e1 then return e2 else skip) = true singleIfReturn(s) = f alse otherwise hasReturn(return e) = true hasReturn(if e then s1 else s2 ) = hasReturn(s1 ) ∨ hasReturn(s2 ) hasReturn(s1 ; s2 ) = hasReturn(s1 ) ∨ hasReturn(s2 ) hasReturn(s) = f alse otherwise

Property A.3 (Methods in Θ must have a return statement). All invoked statements in Θ must contain a return statement. More formally, hasReturns(s) must hold. Property A.4 (Class object references). For each class c ∈ C there exists a metaclass cc ∈ C and a class object reference rc ∈ R such that η (rc ) = cc and ∆(zc ) = rc . We write the class name directly to refer to its class object reference (e.g., Integer denotes zInteger ). Finally, superscripts on environment variables denote successive versions, i.e., ∆1 , ∆2 , ∆3 abbreviate ∆′ , ∆′′ , ∆′′′ rather than exponentiation. Property A.5 (Formal argument usage). All formal arguments of every method body in Θ are used in its statement: − − ∀(→ y .s) ∈ range (Θ). ∀y ∈ → y . isUse (y, s) Property A.6 (No initial concrete return value). The concrete state cannot be in the middle of returning from a method. More formally, it must be that µ=⊥

75

Property A.7 (ηs = η ). The reference typing mapping is carried over unchanged from the concrete semantics, and is never symbolic. Property A.8. No symbolic references: all references r ∈ R in ∆s and Hs are concrete. That is, for all (Id, n) ∈ dom(∆s ), if ∆s (Id, n) ∈ R then ∆s (Id, n) is a concrete reference, and similarly for Hs (r, f ) ∈ R. Property A.9 (Consistent Local Variable Mapping with Symbolic State). Concrete local variable mapping ∆ is consistent with the symbolic local variable mapping ∆s with respect to the path condition π. More formally, we have that ∆ |= (∆s , π ) ≜ (∆, π ) ⇝c true ∧ ∀x ∈ Dom(∆s ).(∆, ∆s (x)) ⇝c v ∧ v = ∆(x)

Property A.10 (Concrete Heap Consistent with Symbolic State). Concrete heap H is consistent with the symbolic local variable mapping ∆s , and symbolic heap Hs with respect to the path condition π. More formally, we have that (∆, H ) |=H (Hs , π ) ≜ ∀(r, f ) ∈ Dom(H ).(∆, Hs (r, f )) ⇝c v ′ ∧ v ′ = H (r, f )

Property A.11 (Symbolic local variable mapping is consistent with respect to the input I ). Input variables are not used in any of the mapped expressions in initial ∆s . More formally, if I is defined as I = getInput(s), for some statement s that is going to be summarized, we have that ∀i ∈ getInputs(s).∀x ∈ Dom(∆s ).¬isU se(i, ∆s (x)) Property A.12 (No ϕ statements appear in s). Let us define the function atM ostSingleIf Return such that

atMostSingleIfReturn(s) = ¬hasReturn(s) ∨ singleIfReturn(s) where singleIfReturn and hasReturn are defined to capture the case where the statement s has at most a single return or none at all.

singleIfReturn(s1 ; s2 ) = ¬hasReturn(s1 ) ∧ singleIfReturn(s2 ) singleIfReturn(if e1 then return e2 else skip) = true singleIfReturn(s) = f alse otherwise hasReturn(return e) = true hasReturn(if e then s1 else s2 ) = hasReturn(s1 ) ∨ hasReturn(s2 ) hasReturn(s1 ; s2 ) = hasReturn(s1 ) ∨ hasReturn(s2 ) hasReturn(s) = f alse otherwise

76

Property A.13 (Rewritten statement always has at most a single return within an if-statement). atMostSingleIfReturn(ŝ) Property A.14 (If statement s has a return statement then s must have a specific form). For some statement s′′ , we have that hasReturn(s) =⇒ (s = s′′ ; if πr then return e else skip) ∧ πr ̸= f alse Property A.15 (πr is true on all return paths). More formally, If Θ ⊢ ((η, ∆, H, ⊥), s) ⇒c (η ′ , ∆′ , H ′ , µ) then µ ̸= ⊥ iff (∆′ , πr ) ⇝c true Property A.16 ( statement s′ has no return statements). More formally, ¬hasReturn(s′ ) is valid. Property A.17 (Fresh variables have u + 1 suffices). More formally, (x, ⊥) is in s, then all its occurrences with s′ must have been renamed to (x, u + 1). Property A.18 (Old input not in s′ ). More formally, Old input does not appear, i.e., is not used in s′ . More formally if (x, j ) ∈ I, then ¬isU se((x, j ), s′ ) Property A.19 (Variables in original statement are not indexed). Given a statement s that has not yet been proceed by JR, i.e., JR’s algorithm has not yet run yet, it must be that all variables in s has not been renamed before. More formally for all x ∈ isU se(s), then x must be of the form (a, ⊥), where a is the name of the variable and ⊥ location indicates that the variable has not been renamed before. Property A.20 (Invoked statements have been prepared and stored in Θt ). This transformation assume that all invoked methods have been transformed and stored in − Θt , where for each c ∈ C, g ∈ G such that → y .s = Θ(c, g ), we have a transformed → − → − ′ definition of y .s of the form (µs , πr ), y .s = transf orm(s)(refer to section B for more detail). Property A.21 (Reference variables always refer to concrete references). ∀z.r = ∆s (z ).r ∈ R, then it must be that r is concrete.

77

Appendix B

Static Transform

Algorithm 3: transform definition: an environment variable without a superscript indicate the initial state Input: to-summarize statement s s1 := γ -creation(s) 2 2 1 3 (πr , s ) := eliminate early-return(s ) 3 3 2 4 (µs , s ) := remove final-return(s ) 3 2 3 5 return ((µs , πr ), s ) 1 2

Theorem B.1 (Transform is Sound). For any statement s, such that µs = ⊥. Also, we assume any concrete δ = (η, ∆, H, ν, µ) If Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν, µ′ ) ((µs , πr ), s′ ) = transf orm(s) Θ ⊢ ((η, ∆, H, ν, µ), s′ ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ )

then η ′ = η ′′ , ∆′ = ∆′′ , H ′ = H ′′ , ν ′ = ν ′′ µ′ = evalReturn(∆′′ , πr , µs ), µ′′ = µ′ Proof To proof this theorem, we apply various transformation from the transform function shown in Fig. 3. We know that according to Corollary 7.2, we have that s −→γ−wrap s1 Θ ⊢ ((η, ∆, H, ν, µ), s) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) such that

Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

The next transformation that the transform function has is the eliminate early-return transformation on the rewritten statement s1 . In particular, we apply theorem 8.2 to get s1 →ret−wrap (πr2 , s2 ) Θ ⊢ ((η, ∆, H, ⊥), s1 ) ⇒c (η2 , ∆2 , H2 , µ2 ) then Θ ⊢ ((η, ∆, H, ⊥), s2 ) ⇒c (η2 , ∆2 , H2 , µ2 ) But, we have just shown from applying the γ-transformation theorem 7.2 that s1 must evaluate in (η, ∆, H, ⊥) to (η ′ , ∆′ , H ′ , ν ′ , µ′ ), then we can conclude that (η2 = η ′ , ∆′ = ∆′ , H2 = H ′ , µ2 = µ′ ). The last transformation applied by the transform function is the remove final-return transformation. In particular we can apply Corollary 9.2 which states that s2 −→f inal−wrap (µ3s , s3 ) Θ ⊢ ((η, ∆, H, ν, µ), s2 ) ⇒c (η3 , ∆3 , H3 , ν3 , µ3 ) then Θ ⊢ ((η, ∆, H, ν, µ), s3 ) ⇒c (η4 , ∆4 , H4 , ν4 , µ4 )

78

η4 = η3 , ∆4 = ∆3 , H4 = H3 , ν4 = ν3 , µ4 = µ µ3 = evalReturn(∆4 , πr2 , µ3s ) ′′

′′

Here we have that η = η4 , ∆ = ∆4 , H ′′ = H4 , ν ′′ = ν4 , µ′′ = µ4 , and πr = πr2 , µs = µ3s . Given that we just established, from before, that Θ ⊢ ((η, ∆, H, ⊥), s2 ) ⇒c (η ′ , ∆′ , H ′ , µ′ ). Therefore, from Corollary 9.2, we have η ′′ = η4 = η3 = η ′ , ∆′′ = ∆4 = ∆3 = ∆′ , H ′′ = H4 = H3 = H ′ , ν ′′ = ν4 = ν3 = ν ′ , and that evalReturn(∆4 , πr2 , µ3s ) = µ3 = µ′ , which is what we wanted to prove. □

79

∆ ⊢ e 1 ⇝ c v1 ∆ ⊢ e ⇝c true

var

∆ ⊢ x ⇝c v

unary−op

∆ ⊢ e ⇝c v ′

∆ ⊢ e 2 ⇝ c v2 ∆ ⊢ e1 ⋄ e2 ⇝c v3

∆ ⊢ e1 ⇝c v

v1 ⋄ v 2 = v 3

∆ ⊢ e ⇝c f alse γ−true

∆ ⊢ γ(e, e1 , e2 ) ⇝c v

v = v′

∆ ⊢ e ⇝c v

v = ∆(x) val

∆ ⊢ v ⇝c v

binary−op

∆ ⊢ e2 ⇝c v γ−false

∆ ⊢ γ(e, e1 , e2 ) ⇝c v ′

′

′′

′′

′

′

Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ) ⇒c (η , ∆ , H , ν , ⊥) ′

′

′

′

′′

′′

′′

Θ ⊢ ((η , ∆ , H , ν , ⊥), s2 ) ⇒c (η , ∆ , H , ν , µ ) composition

Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ; s2 ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ) Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

µ′ ̸= ⊥ composition−ret

Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ; s2 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) ∆ ⊢ e ⇝c v Θ ⊢ ((η, ∆, H, ν, ⊥), x := e) ⇒c (η, ∆[x ← − v], H, ν, ⊥)

assignment

→ −′ ′ ∆ ⊢ z ⇝c r r∈R y .s = Θ(η(r), g) → −′ → −′ → −′ ′ ′ ′ ′ ′ ′ ′ → − v = ∆( y ) Θ ⊢ ((η, {( y , v )}, H, ν, ⊥), s ) ⇒c (η , ∆ , H , ν , µ ) µ ̸= ⊥ − Θ ⊢ ((η, ∆, H, ν, ⊥), invoke(x, z, g, → y )) ⇒ (η ′ , ∆[x ← − µ′ ], H ′ , ν ′ , ⊥)

invoke

c

∆ ⊢ e ⇝c v

return

Θ ⊢ ((η, ∆, H, ν, ⊥), return e) ⇒c (η, ∆, H, ν, v) Θ ⊢ ((η, ∆, H, ν, ⊥), skip) ⇒c (η, ∆, H, ν, ⊥) ∆ ⊢ e ⇝c true

skip

∆ ⊢ e1 ⇝c v1 . . . ∆ ⊢ ek ⇝c vk ′

′

′

′

′

Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η , ∆ , H , ν , ⊥)

∆ [x1 ← v1 , . . . , xk ← vk ]

Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k ))

⇒c (η ′ , ∆′′ , H ′ , ν ′ , ⊥)

if- true

′

∆ ⊢ e ⇝c true

µ ̸= ⊥ ′

′

′

′

′

Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η , ∆ , H , ν , µ ) Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k )) ′

∆ ⊢ e ⇝c f alse

′

′

⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

if- true-ret

′

∆ ⊢ e1 ⇝c v1 . . . ∆ ⊢ ek ⇝c vk ′

′

′

′

′

′ ′ ∆ [x1 ← v1 , . . . , xk ← vk ]

Θ ⊢ ((η, ∆, H, ν, ⊥), s2 ) ⇒c (η , ∆ , H , ν , ⊥)

Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k )) ⇒c (η ′ , ∆′′ , H ′ , ν ′ , ⊥)

if- false

′

∆ ⊢ e ⇝c f alse

µ ̸= ⊥ ′

′

′

′

′

((η, ∆, H, ν, ⊥), s2 ) ⇒c (η , ∆ , H , ν , µ ) Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k )) ∆ ⊢ z ⇝c r

∆ ⊢ e ⇝c v

⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

r∈R

Θ ⊢ ((η, ∆, H, ν, ⊥), put f ield(z, f, e)) ⇒c (η, ∆, H[(r, f ) ← v], ν, ⊥) ∆ ⊢ z ⇝c r

v = H(r, f )

r∈R

Θ ⊢ ((η, ∆, H, ν, ⊥), get f ield(x, z, f )) ⇒c (η, ∆[x ← v], H, ν, ⊥) ′

ν =ν+1

put−field

get−field

′

r = freshRef(ν )

Θ ⊢ ((η, ∆, H, ν, ⊥), new(x, c)) ⇒c (η[r ← c], ∆[x ← r], H, r ′ , ⊥)

Figure 3: Evaluation Rules of Concrete Semantics

80

new

if- false-ret

method-stmt:

Vs = V ⊎ exp → Θs : C × G −→ method(− var.stmt ) ηs : R −→ C ∆s : (Id, n) −→ Vs Hs : R × F −→ Vs µs ∈ Vs ⊎ {⊥} Π = (π, πr , πs ) : Vs × Vs × Vs → Θ : C × G −→ method(− var.stmt )

unique-count:

u∈N

region-variables:

χ = (I, O, T ) : 2V ar × 2V ar × 2V ar

unique-count:

u∈N

vals: method-stmt: ref-type: locals: heap: method-return: path-conditions:

(PC, returnPC, exitPC )

t

(initialized once) (Input, Outputs, Temp)

(initialized once)

Figure 5: Java Ranger’s Environment

′

s −→ret ((πr , µs ), s )

µs ̸= ⊥

πr ̸= f alse ret−wrap

′

s −→ret−wrap (πr , s ; if πr then return µs else skip) s −→ret ((πr , µs ), s)

µs = ⊥

πr = f alse ret−wrap−none

s −→ret−wrap (πr , s) ′

′

′

′

s1 −→ret ((πr , µs ), s1 )

s2 −→ret ((πr , µs ), s2 )

∗ ′ πr = simp(γ(e, πr , πr )

∗ ′ µs = simp(γ(e, µs , µs ))

′ ′ if e then s1 else s2 −→ret ((πr∗ , µ∗ s ), if e then s1 else s2 )

πr = true

µs = e

return e −→ret ((πr , µs ), skip)

ret−if

ret−return

′ ′ ′ ′ s2 −→ret ((πr , µs ), s2 ) ∗ ′ ′ µs = simp(γ(πr , µs , simp(γ(πr , µs , f alse))))

s1 −→ret ((πr , µs ), s1 ) ∗ ′ πr = simp(γ(πr , true, πr ))

ret−comp

′ ′ s1 ; s2 −→ret ((πr∗ , µ∗ s ), s1 ; if (!πr ) then s2 else skip)

isN oOpret (s)

πr = f alse

µs = ⊥

s −→ret ((πr , µs ), s) simp(γ(e, ⊥, ⊥)) = ⊥

simp(γ(e, f alse, f alse)) = f alse

ret−no−op

simp(e) = e

otherwise

Figure 8: Eliminate Early-Return Statements Rules.

πr ̸= f alse

πr = f alse πr ⊢ s −→f inal (⊥, s)

′

s = s ; if πr then return e else skip

final−noop

πr ⊢ s −→f inal (µs , s′ )

Figure 10: Remove Final Return Rules.

81

µs = e final−ret

uniqueu ((I, O, T )) = (uniqueu (I), uniqueu (O), uniqueu (T )) uniqueu (X) = {uniqueu (x) | x ∈ X} ′

u =u+1

′

χ = (I, O, T )

′

u ⊢ s −→rename s

uniqueu ((a, ⊥)) = (a, u) ′

u ⊢ µs

′

′

χ = (I , O , T )

′

s

′′

I = {i1 ..in }

χ = uniqueu′ (χ)

′

′

′

O = {o1 ..om }

′

′

= (i1 , u ) := i1 ; ..; (in , u ) := in ; s ; o1 := (o1 , u ); ..; om := (om , u );

′ 7 rename µs →

′

′

uniqueu ((a, j)) = (a, j) when j ̸= ⊥

′

u ⊢ πr

′ 7 rename πr →

T

′′

′

′

′

= (I ∪ O ∪ T ) rename−wrap

I, O ⊢ ((πr , µs , T, u), s) −→rename−wrap (µ′s , πr′ , T ′′ , u′ ), s′′ )

u ⊢ ⊥ 7→rename ⊥

v : Vs u ⊢ v 7→rename v

rename−bot

′

u ⊢ e 7→rename e rename−val

u ⊢ x 7→rename x

′

rename−var

u ⊢ e2 7→rename e2 7 rename e′1 ⋄ e′2 →

u ⊢ e 1 ⋄ e2

u ⊢ e 7→rename e

′

u ⊢ e 7→rename e

′

u ⊢ e2 7→rename e2

u ⊢ γ(e, e1 , e2 )

7 rename γ(e , e′1 , e′2 ) →

′

u ⊢ x −→rename x

′ rename−assign

→ −′ − u⊢→ y 7→rename y → − − u ⊢ invoke(x, z, g, → y ) −→rename invoke(z ′ , x′ , g, y ′ ) ′

u ⊢ z 7→rename z

′

u ⊢ s1 −→rename s1

u ⊢ e 7→rename e

′

′

′

u ⊢ s2 −→rename s2

u ⊢ if e then s1 else s2 −→rename if e ′

rename−comp

′

u ⊢ s1 −→rename s1

u ⊢ e 7→rename e

′

′ ′ then s1 else s2 )

u ⊢ z 7→rename z

′

rename−if

′

u ⊢ put f ield(z, f, e) −→rename put f ield(z ′ , f, e′ ) u ⊢ x 7→rename x

rename−invoke

′

u ⊢ s2 −→rename s2

−→rename s′1 ; s′2

u ⊢ s 1 ; s2

rename−γ

′

u ⊢ x := e −→rename x′ := e′ u ⊢ x 7→rename x

rename−binaryOp

′

u ⊢ e1 7→rename e1

u ⊢ e 7→rename e

u ⊢ z 7→rename z

rename−putfield

′

′

u ⊢ get f ield(x, z, f ) −→rename get f ield(x , z ′ , f )

rename−getfield

u ⊢ x 7→rename x′ u ⊢ skip −→rename skip

rename−unaryOp

′

′

u ⊢ e1 7→rename e1

x = uniqueu (x)

′

rename−skip

u ⊢ new(x, c) −→rename new(x′ , c)

Figure 11: Renaming Transformation Rules

82

rename−new

x∈I ∆s , I ⊢ x 7→sub ∆s (x)

sub−val

∆s , I ⊢ v 7→sub v

∆s , I ⊢ e 7→sub e

∆s , I ⊢ e 7→sub e

∆s , I ⊢ e2 7→sub e2

∆s , I ⊢ e1 7→sub e1 sub−unaryOp

∆s , I ⊢ e 7→sub e

∆s , I ⊢ e 1 ⋄ e 2

′

′

7 sub e′1 ⋄ e′2 →

∆s , I ⊢ e2 7→sub e2

∆s , I ⊢ γ(e, e1 , e2 ) 7→sub γ(e, e′1 , e′2 )

∆s , I ⊢ µ s

′ 7 sub µs →

I

′

′

sub−γ

′

∆s , I ⊢ πr 7→sub πr

′ ′ = getInput(s ) ∪ getU se(µs ) ∪ getU se(πr ) ′

∆s ⊢ ((πr , µs , I), s) −→sub−wrap ((πr′ , µ′s , I ′ ), s′ ) ∆s , I ⊢ e 7→sub e′

∆s , I ⊢ s1 −→sub s′1

∆s , I ⊢ s2 −→sub s′2

∆s , I ⊢ s1 ; s2 −→sub s′1 ; s′2 → −′ − ∆s , I ⊢ → y 7→sub y

∆s , I ⊢ z 7→sub z

sub−comp

′

→ − − ∆s , I ⊢ invoke(x, z, γ, → y ) −→sub invoke(x, z ′ , γ, y ′ )

sub−invoke

′

∆s , I ⊢ return e −→sub return e′ ∆s , I ⊢ e 7→sub ê

sub−ret

∆s , I ⊢ skip −→sub skip

∆s , I ⊢ s1 −→sub sˆ1

∆s , I ⊢ e 7→sub e

′

sub−skip

∆s , I ⊢ s2 −→sub sˆ2

∆s , I ⊢ if e then s1 else s2 −→sub if ê then sˆ1 else sˆ2 ∆s , I ⊢ z 7→sub z

sub−if

′

∆s , I ⊢ put f ield(z, f, e) −→sub put f ield(z ′ , f, e′ ) ∆s , I ⊢ z 7→sub z

sub−wrap

sub−assign

∆s , I ⊢ x := e −→sub x := e′

∆s , I ⊢ e 7→sub e

sub−binaryOp

′

∆s , I ⊢ e1 7→sub e1

∆s , I ⊢ s −→sub s

sub−var−triv

′

′

′

x∈ /I ∆s , I ⊢ x 7→sub x

sub−var

sub−putfield

′

∆s , I ⊢ get f ield(x, z, f ) −→sub get f ield(x, z ′ , f )

sub−getfield

∆s , I ⊢ new(x, c) −→sub new(x, c)

Figure 12: Input Substitution Rules

83

sub−new

merge(e, P, P ) = (skip, P ) merge(e, P1 , P2 ) when P1 ̸= P2 Let (r, f ) ∈ Dom(P1 ), and (r, f ) ∈ Dom(P2 ) s.t. P1 (r, f ) ̸= P2 (r, f ), Let t1 = P1 (r, f ) ′

P1 = P1 [(r, f ) ← t] ′

t2 = P2 (r, f ) ′

P2 = P2 [(r, f ) ← t]

′

′

′

(sr , Pr ) = merge(e, P1 , P2 ), fresh t. ′ ′ (t := γ(e, t1 , t2 ); sr , Pr )

initialP (Hs ) = {((r, f ), t) | (r, f ) ∈ Dom(Hs ), fresh t} ∀((ri , fi ), ti ) ∈ P, 1 ≤ i ≤ n, n = |P | ̸= 0

addGets(P ) = get f ield(t1 , r1 , f1 ); . . . ; get f ield(tn , rn , fn ) addGets(∅) = skip

∀((ri , fi ), ti ) ∈ P, 1 ≤ i ≤ n, n = |P | ̸= 0

addP uts(P ) = put f ield(r1 , f1 , t1 ); . . . ; put f ield(rn , fn , tn ) addP uts(∅) = skip

P = initialP (Hs )

′

′

T = T ∪ Range(P )

′′

′

′

∆s , Hs ⊢ ((T , P, ⊥), s) −→f ield ((T , P , p), s ) ′′

′

field−wrap

′

∆s , Hs ⊢ ((I, O, T ), s) −→f ield−wrap ((I, O, T ), (addGets(P ); skip; s ; skip; addP uts(P ))

∆s , Hs ⊢ ((T, ∅, ⊤), s) −→f ield ((T, ∅, ⊤), s)

field−no−op

∆s , Hs ⊢ ((T, P, p), x := e) −→f ield ((T, P, p), x := e) ′

r∈R

P = P [(r, f ) ← t]

field−assign

fresh t

∆s , Hs ⊢ ((T, P, ⊥), put f ield(r, f, e)) −→f ield ((T ∪ {t}, P ′ , ⊥), t := e)

field−put

z∈ /R ∆s , Hs ⊢ ((T, P, ⊥), put f ield(z, f, e)) −→f ield ((T, ∅, ⊤), addP uts(P ); put f ield(z, f, e)) r∈R

field−put−var

t = P (r, f )

∆s , Hs ⊢ ((T, P, ⊥), get f ield(x, r, f )) −→f ield ((T, P, ⊥), x := t)

field−get

z∈ /R ∆s , Hs ⊢ ((T, P, ⊥), get f ield(x, z, f )) −→f ield ((T, ∅, ⊤), addP uts(P ); get f ield(x, z, f ))

field−get−var

field−invoke

− − ∆s , Hs ⊢ ((T, P, ⊥), invoke(x, z, γ, → y )) −→f ield ((T, ∅, ⊤), addP uts(P ); invoke(x, z, γ, → y )) ∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T ′ , P ′ , p), s′1 )

∆s , Hs ⊢ ((T ′ , P ′ , p), s2 ) −→f ield ((T ′′ , P ′′ , p′ ), s′2 )

field−comp

∆s , Hs ⊢ ((T, P, ⊥), s1 ; s2 ) −→f ield ((T ′′ , P ′′ , p′ ), s′1 ; s′2 ) ′

′′

(ŝ, P̂ ) = merge(e, P , P ) ′

∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T , P

′

′ , ⊥), s1 )

′

′′

′′

′

∆s , Hs ⊢ ((T , P, ⊥), s2 ) −→f ield ((T , P , ⊥), s2 ) field−if−1

∆s , Hs ⊢ ((T, P, ⊥), if e then s1 else s2 ) −→f ield ((T ′′ , P̂ , ⊥), if e then s′1 else s′2 ; ŝ) ′

′

∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T , ∅, ⊤), s1 )

′

∆s , Hs ⊢ ((T, P, ⊥), if e then s1 else s2 ) −→f ield ((T ′

′

∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T , ∅, ⊤), s1 )

′

′

′

′′

′

field−if−2

, ∅, ⊤), if e then s′1 else s′2 ) ′

′′

′′

′

∆s , Hs ⊢ ((T , P, ⊥), s2 ) −→f ield ((T , P , ⊥), s2 )

∆s , Hs ⊢ ((T, P, ⊥), if e then s1 else s2 ) −→f ield ((T

∆s , Hs ⊢ ((T, P, ⊥), s1 ) −→f ield ((T , P , ⊥), s1 )

′′

∆s , Hs ⊢ ((T , P, ⊥), s2 ) −→f ield ((T , ∅, ⊤), s2 )

′′

, ∅, ⊤), if e then s′1 else (s′2 ; addP uts(P ′′ ))) ′

′′

field−if−3

′

∆s , Hs ⊢ ((T , P, ⊥), s2 ) −→f ield ((T , ∅, ⊤), s2 )

84 ((T ∆s , Hs ⊢ ((T, P, ⊥), if e then s1 else s2 ) −→f ield

′′

, ∅, ⊤), if e then (s′1 ; addP uts(P ′ )) else s′2 )

Figure 14: Field SSA Transformation Rules

field−if−4

′

T ⊢ (∅, s) −→const ∆r

I = Dom(∆r )

′

′

′

′′

′

∆r ∪ ∆s ⊢ ((πr , µs , I ), s) −→sub−wrap ((πr , µs , I ), s ) ∆s , T ⊢ ((µs , πr ), s) x∈T

const−wrapper

−→const−wrap ((πr′ , µ′s , ), s′ ) ∆′r = ∆r [x ← r]

r∈R

T ⊢ (∆r , x := r) −→const ∆′r

const−assign−change

(x ∈ / T ) ∨ (e ∈ / R) T ⊢ (∆r , x := e) −→const ∆r ′

T ⊢ (∆r , s1 ) −→const ∆r

const−assign−no−change

′′

T ⊢ (∆r , s2 ) −→const ∆r

const−if

T ⊢ (∆r , if e then s1 else s2 ) −→const ∆r ′

T ⊢ (∆r , s1 ) −→const ∆r

′

′′

T ⊢ (∆r , s2 ) −→const ∆r

T ⊢ (∆r , s1 ; s2 ) −→const ∆′′ r noOpconst (s) T ⊢ (∆r , s) −→const ∆r

const−comp

const−no−op

Figure 15: Constant Propagation (for References)

85

∆ ⊢ e 1 ⇝ c v1 ∆ ⊢ e ⇝c true

var

∆ ⊢ x ⇝c v

unary−op

∆ ⊢ e ⇝c v ′

∆ ⊢ e 2 ⇝ c v2 ∆ ⊢ e1 ⋄ e2 ⇝c v3

∆ ⊢ e1 ⇝c v

v1 ⋄ v 2 = v 3

∆ ⊢ e ⇝c f alse γ−true

∆ ⊢ γ(e, e1 , e2 ) ⇝c v

v = v′

∆ ⊢ e ⇝c v

v = ∆(x) val

∆ ⊢ v ⇝c v

binary−op

∆ ⊢ e2 ⇝c v γ−false

∆ ⊢ γ(e, e1 , e2 ) ⇝c v ′

′

′′

′′

′

′

Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ) ⇒c (η , ∆ , H , ν , ⊥) ′

′

′

′

′′

′′

′′

Θ ⊢ ((η , ∆ , H , ν , ⊥), s2 ) ⇒c (η , ∆ , H , ν , µ ) composition

Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ; s2 ) ⇒c (η ′′ , ∆′′ , H ′′ , ν ′′ , µ′′ ) Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

µ′ ̸= ⊥ composition−ret

Θ ⊢ ((η, ∆, H, ν, ⊥), s1 ; s2 ) ⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ ) ∆ ⊢ e ⇝c v Θ ⊢ ((η, ∆, H, ν, ⊥), x := e) ⇒c (η, ∆[x ← − v], H, ν, ⊥)

assignment

→ −′ ′ ∆ ⊢ z ⇝c r r∈R y .s = Θ(η(r), g) → −′ → −′ → −′ ′ ′ ′ ′ ′ ′ ′ → − v = ∆( y ) Θ ⊢ ((η, {( y , v )}, H, ν, ⊥), s ) ⇒c (η , ∆ , H , ν , µ ) µ ̸= ⊥ − Θ ⊢ ((η, ∆, H, ν, ⊥), invoke(x, z, g, → y )) ⇒ (η ′ , ∆[x ← − µ′ ], H ′ , ν ′ , ⊥)

invoke

c

∆ ⊢ e ⇝c v

return

Θ ⊢ ((η, ∆, H, ν, ⊥), return e) ⇒c (η, ∆, H, ν, v) Θ ⊢ ((η, ∆, H, ν, ⊥), skip) ⇒c (η, ∆, H, ν, ⊥) ∆ ⊢ e ⇝c true

skip

∆ ⊢ e1 ⇝c v1 . . . ∆ ⊢ ek ⇝c vk ′

′

′

′

′

Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η , ∆ , H , ν , ⊥)

∆ [x1 ← v1 , . . . , xk ← vk ]

Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k ))

⇒c (η ′ , ∆′′ , H ′ , ν ′ , ⊥)

if- true

′

∆ ⊢ e ⇝c true

µ ̸= ⊥ ′

′

′

′

′

Θ ⊢ ((η, ∆, H, ν, µ), s1 ) ⇒c (η , ∆ , H , ν , µ ) Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k )) ′

∆ ⊢ e ⇝c f alse

′

′

⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

if- true-ret

′

∆ ⊢ e1 ⇝c v1 . . . ∆ ⊢ ek ⇝c vk ′

′

′

′

′

′ ′ ∆ [x1 ← v1 , . . . , xk ← vk ]

Θ ⊢ ((η, ∆, H, ν, ⊥), s2 ) ⇒c (η , ∆ , H , ν , ⊥)

Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k )) ⇒c (η ′ , ∆′′ , H ′ , ν ′ , ⊥)

if- false

′

∆ ⊢ e ⇝c f alse

µ ̸= ⊥ ′

′

′

′

′

((η, ∆, H, ν, ⊥), s2 ) ⇒c (η , ∆ , H , ν , µ ) Θ ⊢ ((η, ∆, H, ν, ⊥), if e then s1 else s2 ; ϕ(x1 , e1 , e′1 ) . . . ϕ(xk , ek , e′k )) ∆ ⊢ z ⇝c r

∆ ⊢ e ⇝c v

⇒c (η ′ , ∆′ , H ′ , ν ′ , µ′ )

r∈R

Θ ⊢ ((η, ∆, H, ν, ⊥), put f ield(z, f, e)) ⇒c (η, ∆, H[(r, f ) ← v], ν, ⊥) ∆ ⊢ z ⇝c r

v = H(r, f )

r∈R

Θ ⊢ ((η, ∆, H, ν, ⊥), get f ield(x, z, f )) ⇒c (η, ∆[x ← v], H, ν, ⊥) ′

ν =ν+1

put−field

get−field

′

r = freshRef(ν )

Θ ⊢ ((η, ∆, H, ν, ⊥), new(x, c)) ⇒c (η[r ← c], ∆[x ← r], H, r ′ , ⊥)

new

Figure B1: Evaluation Rules of Concrete Semantics

86

if- false-ret

References [1] Baldoni, R., Coppa, E., D’Elia, D.C., Demetrescu, C., Finocchi, I.: A survey of symbolic execution techniques. ACM Comput. Surv. 51(3) (2018) [2] Luckow, K., Dimjašević, M., Giannakopoulou, D., Howar, F., Isberner, M., Kahsai, T., Rakamarić, Z., Raman, V.: JDart: A dynamic symbolic analysis framework. In: Chechik, M., Raskin, J.-F. (eds.) Proceedings of the 22nd International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS). Lecture Notes in Computer Science, vol. 9636, pp. 442–459. Springer, Berlin, Heidelberg (2016) [3] Sen, K., Agha, G.: Cute and jcute: Concolic unit testing and explicit path modelchecking tools. In: Ball, T., Jones, R.B. (eds.) Computer Aided Verification, pp. 419–423. Springer, Berlin, Heidelberg (2006) [4] Nguyen, T., Dwyer, M.B., Visser, W.: Symlnfer: Inferring program invariants using symbolic states. In: 2017 32nd IEEE/ACM International Conference on Automated Software Engineering (ASE), pp. 804–814 (2017). https://doi.org/10. 1109/ASE.2017.8115691 [5] Hussein, S., Rayadurgam, S., McCamant, S., Sharma, V., Heimdahl, M.: Counterexample-guided inductive repair of reactive contracts. In: Proceedings of the IEEE/ACM 10th International Conference on Formal Methods in Software Engineering. FormaliSE ’22, pp. 46–57. Association for Computing Machinery, New York, NY, USA (2022). https://doi.org/10.1145/3524482.3527650 . https://doi.org/10.1145/3524482.3527650 [6] Ramos, D.A., Engler, D.R.: Practical, low-effort equivalence verification of real code. In: Proceedings of the 23rd International Conference on Computer Aided Verification. CAV’11, pp. 669–685. Springer, Berlin, Heidelberg (2011). http://dl.acm.org/citation.cfm?id=2032305.2032360 [7] Sharma, V., Hietala, K., McCamant, S.: Finding Substitutable Binary Code By Synthesizing Adaptors. In: 11th IEEE Conference on Software Testing, Validation and Verification (ICST) (2018) [8] Stephens, N., Grosen, J., Salls, C., Dutcher, A., Wang, R., Corbetta, J., Shoshitaishvili, Y., Kruegel, C., Vigna, G.: Driller: Augmenting Fuzzing Through Selective Symbolic Execution. In: 23rd Annual Network and Distributed System Security Symposium, NDSS 2016, San Diego, California, USA, February 21-24, 2016, pp. 1–16. The Internet Society, San Diego, CA (2016) [9] Shoshitaishvili, Y., Wang, R., Salls, C., Stephens, N., Polino, M., Dutcher, A., Grosen, J., Feng, S., Hauser, C., Krügel, C., Vigna, G.: SOK: (state of) the art of war: Offensive techniques in binary analysis. In: IEEE Symposium on Security and Privacy, SP 2016, San Jose, CA, USA, May 22-26, 2016, pp. 138–157. IEEE

87

Computer Society, Los Alamitos, CA, USA (2016). https://doi.org/10.1109/SP. 2016.17 . https://doi.org/10.1109/SP.2016.17 [10] : ISSTA 2014: Proceedings of the 2014 International Symposium on Software Testing and Analysis. Association for Computing Machinery, New York, NY, USA (2014) [11] Sun, W., Xu, L., Elbaum, S.: Improving the cost-effectiveness of symbolic testing techniques for transport protocol implementations under packet dynamics. In: Proceedings of the 26th ACM SIGSOFT International Symposium on Software Testing and Analysis. ISSTA 2017, pp. 79–89. ACM, New York, NY, USA (2017). https://doi.org/10.1145/3092703.3092706 . http://doi.acm.org/10.1145/3092703.3092706 [12] SV-COMP 2026: 15th International Competition on Software Verification. https: //sv-comp.sosy-lab.org/2026/. Held at TACAS 2026, Torino, Italy, April 13, 2026 (2026) [13] SV-COMP 2026: Definitions and Rules. https://sv-comp.sosy-lab.org/2026/rules. php. 15th International Competition on Software Verification, held at TACAS 2026, Torino, Italy (2026) [14] Hansen, T., Schachte, P., Søndergaard, H.: State joining and splitting for the symbolic execution of binaries. In: Runtime Verification, 9th International Workshop, RV 2009, Grenoble, France, June 26-28, 2009. Selected Papers, pp. 76–92 (2009) [15] Kuznetsov, V., Kinder, J., Bucur, S., Candea, G.: Efficient state merging in symbolic execution. In: Proceedings of the 33rd ACM SIGPLAN Conference on Programming Language Design and Implementation. PLDI ’12, pp. 193–204. ACM, New York, NY, USA (2012) [16] Sen, K., Necula, G., Gong, L., Choi, W.: Multise: Multi-path symbolic execution using value summaries. In: Proceedings of the 2015 10th Joint Meeting on Foundations of Software Engineering. ESEC/FSE 2015, pp. 842–853. ACM, New York, NY, USA (2015). https://doi.org/10.1145/2786805.2786830 [17] Avgerinos, T., Rebert, A., Cha, S.K., Brumley, D.: Enhancing symbolic execution with veritesting. In: Proceedings of the 36th International Conference on Software Engineering. ICSE 2014, pp. 1083–1094. ACM, New York, NY, USA (2014). https: //doi.org/10.1145/2568225.2568293 [18] Păsăreanu, C.S., Visser, W., Bushnell, D., Geldenhuys, J., Mehlitz, P., Rungta, N.: Symbolic pathfinder: integrating symbolic execution with model checking for java bytecode analysis. Automated Software Engineering 20(3), 391–425 (2013) https://doi.org/10.1007/s10515-013-0122-2 [19] Pnueli, A., Siegel, M., Singerman, E.: Translation validation. In: Steffen, B. (ed.)

88

Tools and Algorithms for Construction and Analysis of Systems, 4th International Conference, TACAS ’98, Held as Part of the European Joint Conferences on the Theory and Practice of Software, ETAPS’98, Lisbon, Portugal, March 28 - April 4, 1998, Proceedings. Lecture Notes in Computer Science, pp. 151–166. Springer, Berlin, Heidelberg (1998). https://doi.org/10.1007/BFB0054170 [20] Necula, G.C.: Translation validation for an optimizing compiler. In: Lam, M.S. (ed.) Proceedings of the 2000 ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI), Vancouver, British Columbia, Canada, June 18-21, 2000, pp. 83–94. ACM, New York, NY, USA (2000). https://doi.org/10.1145/349299.349314 [21] Lopes, N.P., Lee, J., Hur, C., Liu, Z., Regehr, J.: Alive2: bounded translation validation for LLVM. In: Freund, S.N., Yahav, E. (eds.) PLDI ’21: 42nd ACM SIGPLAN International Conference on Programming Language Design and Implementation, Virtual Event, Canada, June 20-25, 2021, pp. 65–79. ACM, New York, NY, USA (2021). https://doi.org/10.1145/3453483.3454030 [22] Leroy, X.: Formal verification of a realistic compiler. Commun. ACM 52(7), 107– 115 (2009) https://doi.org/10.1145/1538788.1538814 [23] Kumar, R., Myreen, M.O., Norrish, M., Owens, S.: CakeML: a verified implementation of ML. In: Jagannathan, S., Sewell, P. (eds.) The 41st Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL ’14, San Diego, CA, USA, January 20-21, 2014, pp. 179–192. ACM, New York, NY, USA (2014). https://doi.org/10.1145/2535838.2535841 [24] Zhao, J., Nagarakatte, S., Martin, M.M.K., Zdancewic, S.: Formal verification of SSA-based optimizations for LLVM. In: Boehm, H., Flanagan, C. (eds.) ACM SIGPLAN Conference on Programming Language Design and Implementation, PLDI ’13, Seattle, WA, USA, June 16-19, 2013, pp. 175–186. ACM, New York, NY, USA (2013). https://doi.org/10.1145/2491956.2462164 [25] Lopes, N.P., Menendez, D., Nagarakatte, S., Regehr, J.: Provably correct peephole optimizations with Alive. In: Grove, D., Blackburn, S.M. (eds.) Proceedings of the 36th ACM SIGPLAN Conference on Programming Language Design and Implementation, Portland, OR, USA, June 15-17, 2015, pp. 22–32. ACM, New York, NY, USA (2015). https://doi.org/10.1145/2737924.2737965 [26] VanHattum, A., Pardeshi, M., Fallin, C., Sampson, A., Brown, F.: Lightweight, modular verification for WebAssembly-to-native instruction selection. In: Gupta, R., Abu-Ghazaleh, N.B., Musuvathi, M., Tsafrir, D. (eds.) Proceedings of the 29th ACM International Conference on Architectural Support for Programming Languages and Operating Systems, Volume 1, ASPLOS 2024, La Jolla, CA, USA, 27 April 2024- 1 May 2024, pp. 231–248. ACM, New York, NY, USA (2024). https://doi.org/10.1145/3617232.3624862

89

[27] Brown, F., Renner, J., Nötzli, A., Lerner, S., Shacham, H., Stefan, D.: Towards a verified range analysis for JavaScript JITs. In: Donaldson, A.F., Torlak, E. (eds.) Proceedings of the 41st ACM SIGPLAN International Conference on Programming Language Design and Implementation, PLDI 2020, London, UK, June 15-20, 2020, pp. 135–150. ACM, New York, NY, USA (2020). https://doi.org/10. 1145/3385412.3385968 [28] Schwartz, E.J., Avgerinos, T., Brumley, D.: All you ever wanted to know about dynamic taint analysis and forward symbolic execution (but might have been afraid to ask). In: 31st IEEE Symposium on Security and Privacy, SP 2010, 1619 May 2010, Berleley/Oakland, California, USA, pp. 317–331. IEEE Computer Society, Washington, DC, USA (2010). https://doi.org/10.1109/SP.2010.26 [29] De Boer, F.S., Bonsangue, M.M.: Symbolic execution formally explained. Formal Aspects Comput. 33(4-5), 617–636 (2021) https://doi.org/10.1007/ S00165-020-00527-Y [30] Voogd, E., Kløvstad, Å.A.A., Johnsen, E.B., Wasowski, A.: Compositional symbolic execution semantics. Theor. Comput. Sci. 1044, 115263 (2025) https: //doi.org/10.1016/J.TCS.2025.115263 [31] Porncharoenwase, S., Nelson, L., Wang, X., Torlak, E.: A formal foundation for symbolic evaluation with merging. Proc. ACM Program. Lang. 6(POPL), 1–28 (2022) https://doi.org/10.1145/3498709 [32] Bilardi, G., Pingali, K.: Algorithms for computing the static single assignment form. J. ACM 50(3), 375–425 (2003) https://doi.org/10.1145/765568.765573 [33] A Formal Semantics for Java Symbolic Evaluation using LargeBlock Encoding: Technical Report. https://drive.google.com/file/d/ 1Id1PS9O6Wk78ceGRe1CHOWx pA8OaCeC/view?usp=sharing (2026)

90

Related documents

Record · ID 429424 · SHA-256 0bb4c062448692a9
Retrieved via Conceptio: every document is proof-bundled with source, license, and retrieval metadata.
Bring this data into your agent: Connect via MCP or API · 20 free credits to start · no card required
Read the Docs → · View CLI source on GitHub · Conceptio Open Knowledge Archive