Topics Problem: call graph construction in OO languages applications: inlining or static dispatch if only one better interprocedural analysis results Consider Featherweight Java --------------------------- L ::= class C extends C { C_seq f_seq; K M_seq } K ::= C(C_seq f_seq) { super (f_seq); this.f_seq = f_seq; } M ::= C m(C_seq x_seq) { return e; } e ::= x | e.f | e.m(e_seq) | new C(e_seq) | (C) e Class Hierarchy Analysis ------------------------ Example class A class B extends A class C extends B B x = makeObject() x.foo(); Approach use types, enumerate methods in types that match Rapid Type Analysis ------------------- Motivation main creates A, calls A.bar in a loop A.bar creates a B, returns it C.bar creates a D what impls could the bar() in main() invoke? Approach add main to worklist recursively take method off the worklist for each class C created if C was not considered before add all methods in C that are called to the worklist for each method m called if m was not considered before add all impls of m in C's that have been considered Example program for which 0-CFA will work but be slower than RTA ---------------------------------------------------------------- A.foo(x) { return x; } B.foo(x) { return new D(); } D.foo(x) { return new A(); } main() x = new A() loop x = x.foo(new B()); // calls A.foo() or B.foo() or D.foo() y = new C(); y.foo(x) // only calls C.foo(); Approach at each program point, map var to set of classes map each inst var to set of classes do context-insensitive interprocedural analysis BUT: call graph updates along with everything! Context-sensitive call graph construction ----------------------------------------- foo(x) { return x } x = foo(new A()); x.bar(); y = foo(new B()); y.bar(); MORE SENSITIVITY NEEDED IF foo(x) { return baz(x); } baz(x) { return x; } k-CFA analysis grove/chambers framework instance variable map: (variable, variable key) -> set of (class, class key) procedure map: (procedure, procedure key) -> var -> set of (class, class key) // var includes return O-CFA: all keys are just unit k-CFA: proc key is a k-sequence of last calling locations CPA: proc key is a tuple of classes (one per parameter) SCS: proc key is a tuple of sets of classes (one set per parameter) more complex in theory than CPA but often has fewer contours in practice k-object-sensitive-m-heap: proc key is k-tuple of allocation sites for receiver (and receiver of method where that receiver was allocated, etc.) class key is m+1 tuple of allocation site of object + m receivers inst var key same as class key of above, only scale to 1-CFA (at best)