710 likes | 729 Views
Compositional Pointer and Escape Analysis for Java Programs. John Whaley IBM Tokyo Research Laboratory. Martin Rinard Laboratory for Computer Science MIT. Analysis Points-to information Escape information Optimizations Stack allocation Synchronization elimination. Outline.
E N D
Compositional Pointer and Escape Analysis for Java Programs John Whaley IBM Tokyo Research Laboratory Martin Rinard Laboratory for Computer Science MIT
Analysis Points-to information Escape information Optimizations Stack allocation Synchronization elimination
Outline • Example • Analysis Algorithm • Optimizations • Experimental Results • Conclusion
Employee Database Example • Read in database of employee records • Extract statistics like max salary
Vector John Doe Ben Bit Jane Roe $45,000 $30,000 $55,000 Employee Database Example • Read in database of employee records • Extract statistics like max salary Name Salary
Computing Max Salary • Traverse Records to Find Max Salary Vector Name John Doe Ben Bit Jane Roe Salary $45,000 $30,000 $55,000 max = $0
Computing Max Salary • Traverse Records to Find Max Salary Vector Name John Doe Ben Bit Jane Roe Salary $45,000 $30,000 $55,000 max = $45,000 who = John Doe
Computing Max Salary • Traverse Records to Find Max Salary Vector Name John Doe Ben Bit Jane Roe Salary $45,000 $30,000 $55,000 max = $45,000 who = John Doe
Computing Max Salary • Traverse Records to Find Max Salary Vector Name John Doe Ben Bit Jane Roe Salary $45,000 $30,000 $55,000 max = $55,000 who = Jane Roe
Computing Max Salary • Traverse Records to Find Max Salary Vector Name John Doe Ben Bit Jane Roe Salary $45,000 $30,000 $55,000 max salary = $55,000 highest paid = Jane Roe
Coding Max Computation class EmployeeDatabase { Vector database = new Vector(); Employee highestPaid; void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } }
Coding Max Computation class EmployeeDatabase { Vector database = new Vector(); Employee highestPaid; void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } }
Issues In Implementation • Enumeration object allocated on heap • Increases heap memory usage • Increases garbage collection frequency • Heap allocation is unnecessary • Enumeration object allocated inside max • Not accessible outside max • Should be able to use stack allocation
Key Concept • Enumeration object is capturedin max • Allocated inside computation of method • Inaccessible to callers of method • Within method, object does not escape to another thread • So object is dead when method returns • Can allocate captured objects on stack
How is Database Used? void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); }
Interesting Fact void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } • Only one thread accesses employee database • But accesses are synchronized! Employee e = enum.nextElement();
Synchronization in nextElement class VectorEnumerator implements Enumeration { Vector vector; int count; Object nextElement() { synchronized (vector) { if (count < vector.elementCount) return vector.elementData[count++]; } throw new NoSuchElementException(); } }
Synchronized Libraries • nextElement is in the Java class library • Java is a multithreaded language • By default, libraries are synchronized • Result: lots of unnecessary synchronization for objects that are accessed by only one thread
Eliminating Unnecessary Synchronization • Captured objects are accessible to only one thread • Can eliminate synchronization on captured objects
Basic Idea • Use pointer and escape analysis to recognize captured objects • Transform program to • Allocate captured objects on stack • Eliminate synchronization on captured objects
Analysis Overview • Interprocedural analysis • Compositional analysis • Driving Principle • Explicitly represent potential interactions of method with its environment (callers and other threads)
Points-to Escape Graph in Example void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } dotted = outside [ ] vector elementData solid = inside enum database highestPaid this e
Definitions: node types • NI = inside nodes • represent objects created within the computation of the method • one inside node for each object creation site; represents all objects created at site • NO = outside nodes • represent objects created outside of the computation of the method
Definitions: outside node types NP = parameter nodes represent objects passed as incoming parameters NL = load nodes one load node for each load statement in method represents objects loaded from an escaped node NCL = class nodes node from which static variables are accessed
Points-to Escape Graph in Example void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } dotted = outside [ ] vector elementData solid = inside enum database highestPaid this e
Points-to Escape Graph in Example void computeMax() { int max = 0; Enumeration enum = database.elements(); while (enum.hasMoreElements()) { Employee e = enum.nextElement(); if (max < e.salary()) { max = e.salary(); highestPaid = e; } } } dotted = outside [ ] vector elementData solid = inside enum database highestPaid red = escaped white = captured this e
Escaped nodes • Escaped nodes • parameter nodes • class nodes • thread nodes • nodes in return set • nodes reachable from other escaped nodes • captured is the opposite of escaped
Dataflow Analysis • Computes a points-to escape graph for each program point • Points-to escape graph is a triple <I,O,e> • I - set of inside edges • O - set of outside edges • e - escape function
Dataflow Analysis • Initial state: I : formals point to parameter nodes, classes point to class nodes O: Ø • Transfer functions: I´ = (I – KillI) U GenI O´ = O U GenO • Confluence operator is U
Intraprocedural Analysis • Must define transfer functions for: • copy statement l = v • load statement l1 = l2.f • store statement l1.f = l2 • return statement return l • object creation site l = new cl • method invocation l = l0.op(l1…lk)
copy statement l = v KillI= edges(I, l) GenI= {l} × succ(I, v) I´ = (I – KillI) GenI Existing edges l v
copy statement l = v KillI= edges(I, l) GenI= {l} × succ(I, v) I´ = (I – KillI) GenI Generated edges l v
load statement l1 = l2.f SE= {n2 succ(I, l2) . escaped(n2)} SI= {succ(I, n2,.f) . n2 succ(I, l2)} case 1: l2 does not point to an escaped node (SE= Ø) KillI= edges(I, l1) GenI= {l1} × SI Existing edges l1 f l2
load statement l1 = l2.f SE= {n2 succ(I, l2) . escaped(n2)} SI= {succ(I, n2,.f) . n2 succ(I, l2)} case 1: l2 does not point to an escaped node (SE= Ø) KillI= edges(I, l1) GenI= {l1} × SI Generated edges l1 f l2
load statement l1 = l2.f case 2: l2 does point to an escaped node (SEØ) KillI= edges(I, l1) GenI= {l1} × (SI {n}) GenO= (SE× {f}) × {n} Existing edges l1 l2
load statement l1 = l2.f case 2: l2 does point to an escaped node (SEØ) KillI= edges(I, l1) GenI= {l1} × (SI {n}) GenO= (SE× {f}) × {n} Generated edges l1 f l2
store statement l1.f = l2 GenI= (succ(I, l1) × {f}) × succ(I, l2) I´ = I GenI Existing edges l1 l2
store statement l1.f = l2 GenI= (succ(I, l1) × {f}) × succ(I, l2) I´ = I GenI Generated edges l1 f l2
object creation site l = new cl KillI= edges(I, l) GenI= {<l, n>} Existing edges l
object creation site l = new cl KillI= edges(I, l) GenI= {<l, n>} Generated edges l
Method call • Transfer function for method call: • Take points-to escape graph before the call site • Retrieve the points-to escape graph from analysis of callee • Map callee graph into caller graph • Result is the points-to escape graph after the call site
Interprocedural Mapping • Set up an abstract mapping between caller and callee • outside nodes in the callee may refer to any number of inside nodes in the caller • add all reachable inside edges from callee’s graph into caller’s graph • outside edges from a node in the callee need to be added to the mapped caller node if it escapes
Interprocedural Mapping Example void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); }
Interprocedural Mapping Example void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } graph before call site [ ] database elementData e
Interprocedural Mapping Example void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } graph before call site [ ] database elementData e callee graph [ ] database elementData this highestPaid Enum object is not present because it was captured in the callee.
Step 1: Map formals to actuals void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } graph before call site [ ] database elementData e callee graph [ ] database elementData this highestPaid
Step 1: Map formals to actuals void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } graph before call site [ ] database elementData e highestPaid database callee graph [ ] elementData
Step 2: Match callee outside edges against caller inside edges void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } graph before call site [ ] database elementData e highestPaid database callee graph [ ] elementData
Step 2: Match callee outside edges against caller inside edges void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } graph before call site [ ] database elementData e elementData callee graph [ ]
Step 2: Match callee outside edges against caller inside edges void printStatistics() { BufferedReader r = new BufferedReader( new InputStreamReader(System.in)); EmployeeDatabase e = new EmployeeDatabase(r); e.computeMax(); System.out.println(“max salary = “ + e.highestPaid); } graph before call site [ ] database elementData e elementData callee graph [ ]