710 likes | 739 Views
Explore compositional pointer and escape analysis for Java programs, optimization strategies, experimental results, and more using examples like Employee Database. Understand issues in implementation and ways to eliminate unnecessary synchronizations. Learn about captured objects and stack allocation to enhance program efficiency.
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 [ ]