compositional pointer and escape analysis for java programs martin rinard laboratory for computer...

Post on 20-Dec-2015

216 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Compositional Pointer and Escape Analysis for Java Programs

Martin RinardLaboratory for

Computer ScienceMIT

John Whaley IBM TokyoResearch

Laboratory

AnalysisPoints-to informationEscape information

OptimizationsStack 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

Employee Database Example

• Read in database of employee records• Extract statistics like max salary

Name

Salary

John Doe

$45,000

Ben Bit

$30,000

Jane Roe

$55,000

Vector

Computing Max Salary

• Traverse Records to Find Max Salary

John Doe

$45,000

Name

Salary

Ben Bit

$30,000

Jane Roe

$55,000

Vector

max = $0

Computing Max Salary

• Traverse Records to Find Max Salary

John Doe

$45,000

Name

Salary

Ben Bit

$30,000

Jane Roe

$55,000

Vector

max = $45,000

who = John Doe

Computing Max Salary

• Traverse Records to Find Max Salary

John Doe

$45,000

Name

Salary

Ben Bit

$30,000

Jane Roe

$55,000

Vector

max = $45,000

who = John Doe

Computing Max Salary

• Traverse Records to Find Max Salary

John Doe

$45,000

Name

Salary

Ben Bit

$30,000

Jane Roe

$55,000

Vector

max = $55,000

who = Jane Roe

Computing Max Salary

• Traverse Records to Find Max Salary

John Doe

$45,000

Name

Salary

Ben Bit

$30,000

Jane Roe

$55,000

Vector

max salary = $55,000

highest paid = Jane Roe

Coding Max Computationclass 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 Computationclass 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 captured in 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

vector elementData [ ]

this

enum

e

dotted = outside

solid = inside

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; }

}

}

database highestPaid

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

vector elementData [ ]

this

enum

e

dotted = outside

solid = inside

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; }

}

}

database highestPaid

Points-to Escape Graph in Example

red = escaped

white = captured

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

solid = insidevector elementData [ ]

this

enum

e

database highestPaid

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

l

v

Existing edges

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

l1

l2

Existing edges

f

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

l2

f

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}

l1

l2

Existing edges

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

l2

f

store statement l1.f = l2

GenI = (succ(I, l1) × {f}) × succ(I, l2)

I´ = I GenI

l2

Existing edges

l1

store statement l1.f = l2

GenI = (succ(I, l1) × {f}) × succ(I, l2)

I´ = I GenI

Generated edges

l2

l1f

object creation site l = new cl

KillI = edges(I, l)

GenI = {<l, n>}

l

Existing edges

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 Examplevoid 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

egraph before call site

elementData [ ]database

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

callee graph

graph before call site

Enum object is not present because it was captured in the callee.

elementData [ ]this database

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

highestPaid

Step 1: Map formals to actuals

graph before call site

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

callee graph

elementData [ ]this database

highestPaid

Step 1: Map formals to actuals

graph before call site

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

callee graph

elementData [ ]

database

highestPaid

Step 2: Match callee outside edges against caller inside edges

graph before call site

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

elementData [ ]callee graph

database

highestPaid

Step 2: Match callee outside edges against caller inside edges

graph before call site

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

elementData

[ ]callee graph

Step 2: Match callee outside edges against caller inside edges

graph before call site

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

callee graph

elementData

[ ]

Step 2: Match callee outside edges against caller inside edgesvoid 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

e elementData [ ]database

callee graph

[ ]highestPaid

Step 2: Match callee outside edges against caller inside edgesvoid 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

e elementData [ ]database

callee graph

[ ]highestPaid

Step 2: Match callee outside edges against caller inside edgesvoid 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

e elementData [ ]database

highestPaid

callee graph

Step 3: Add nodes and edges and update escape function

graph before call site

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

highestPaid

Step 3: Add nodes and edges and update escape function

final graph:

Escaped nodes and edges in callee may be recaptured in caller!

e elementData [ ]database

void printStatistics() {BufferedReader r = new BufferedReader(

new InputStreamReader(System.in));EmployeeDatabase e = new EmployeeDatabase(r);e.computeMax();System.out.println(“max salary = “ + e.highestPaid);

}

highestPaid

Life is not so Simple

• Dependences between phases• Mapping best framed as constraint

satisfaction problem• Solved using constraint satisfaction

Algorithm Features

• Partial program analysis• can analyze libraries independent of

callers• can analyze a method without

analyzing the methods it invokes• Appropriate for a dynamic compiler

• Support for partial program analysis• Analyze libraries offline and use

results

Stack Allocation of Captured Objects

• Objects that are captured can be allocated in stack frame of capturing method

Stack before

fp

e: null

enum:

max: 0 obj header

vect: null

index: 0

Stack Allocation of Captured Objects

• Objects that are captured can be allocated on the stack

fp

e: null

enum:

max: 0 obj header

vect: null

index: 0

Stack before

fp

e: null

max: 0obj

headervect: null

index: 0

Stack after

Stack Allocation of Captured Objects

• Stack allocation can extend lifetime of objects

• Allocations of arbitrary size are not transformed• Allocation sites inside loops• Arbitrary-sized arrays

Object captured within a caller

• Call path to the allocating method is specialized

• Add an extra parameter: location in the caller’s stack frame where to put the object

• Object allocation is changed to allocate the object at the given location, rather than on the heap

Specialization policy

• Distance in the call graph between capturing method and allocating method may be large

• Implemented solution: full specialization• Specialized versions of all methods on

call chain from capturing method to allocating method

• Does not seem to blow up in practice

Removing Synchronization on Captured Objects

• Identify lock-unlock pairs that can only operate on captured objects• Augment analysis with sets of nodes

for each lock-unlock pair• If all nodes in a set are captured, then

the lock-unlock pair can be removed

Experimental Results

• Implemented in the Jalapeño JVM• Analysis performed on the entire VM

• Including the analysis code itself!

Benchmark Lines ofcode

Class fi lesize (bytes)

javac - 87801

javacup 10574 157057javalex 8159 95229pbob 18370 253752J VM 70536 456494

Synch Operations Eliminated

36%

67%

48%

24%

0%

10%

20%

30%

40%

50%

60%

70%

80%

90%

100%

j avac j avacup j avalex pbob

Stack Allocated Objects

29%22%

95%

30%

0%

10%

20%

30%

40%

50%

60%

70%

80%

90%

100%

j avac j avacup j avalex pbob

Size of Stack Allocated Objects

25%20%

92%

30%

0%

10%

20%

30%

40%

50%

60%

70%

80%

90%

100%

j avac j avacup j avalex pbob

Related Work

• Pointer Analysis for Sequential Programs• Chatterjee, Ryder, Landi (POPL 99)• Sathyanathan & Lam (LCPC 96)• Steensgaard (POPL 96)• Wilson & Lam (PLDI 95)• Emami, Ghiya, Hendren (PLDI 94)• Choi, Burke, Carini (POPL 93)

Related Work

• Pointer Analysis for Multithreaded Programs• Rugina and Rinard (PLDI 99) (fork-

join parallelism, not compositional)• We have extended our points-to analysis

for multithreaded programs (irregular, thread-based concurrency, compositional)

• Escape Analysis• Blanchet (POPL 98)• Deutsch (POPL 90, POPL 97)• Park & Goldberg (PLDI 92)

Related Work

• Synchronization Optimizations• Diniz & Rinard (LCPC 96, POPL 97)• Plevyak, Zhang, Chien (POPL 95)• Aldrich, Chambers, Sirer, Eggers

(SAS99)• Blanchet (OOPSLA 99)• Bogda, Hoelzle (OOPSLA 99)• Choi, Gupta, Serrano, Sreedhar, Midkiff

(OOPSLA 99)

Conclusion

• Combined points-to and escape analysis• Interprocedural• Compositional - Inside and outside

nodes/edges• Implemented in Jalapeño• Encouraging experimental results

top related