3. Jax Project Background & Goals
• successful project at IBM Research from 1998-2003
• goal:
- originally: shrink Java applications so that they can be downloaded faster,
especially over slow connections
- later: optimize Java applications running on embedded devices
• approach:
- static analysis (but rely on user to specify reflective behaviors and dynamic
class loading)
- program transformations (e.g. merging classes)
• applications:
- open-source release via alphaworks
- used by various IBM teams and IBM customers (e.g. apps running on
Wimbledon website)
- integrated in Smartlinker component of IBM WebSphere Device Developer
• contributors: Aldo Eisma, Chris Laffra, Jens Palsberg, David Streeter, Peter
Sweeney, Frank Tip
3
OOPSLA’99
4. What did it do?
• call graph construction
• removal of dead methods & dead fields
- also: removal of method bodies, write-only fields
• inlining of small methods
• class hierarchy transformations
• name compression
• constant pool compression
4
5. Call Graph Construction
• Jax relied on type-based algorithms
- Class Hierarchy Analysis (CHA) [Dean et al. 1995]
- Rapid Type Analysis (RTA) [Bacon 1997]
- XTA [Tip & Palsberg 2000]
• considerations:
- efficiency: scaled to thousands of classes
- simplicity: no need for construction of CFGs, SSA Form, pointer
analysis, …
- need to handle incomplete applications (Jax did not analyze the
code in Java’s standard libraries but made conservative
assumptions, in the spirit of Averroes [Ali 2013)
5
6. Example
public static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
7. Precise Call Graph
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
4 edges
7
8. XTA Algorithm for Call Graph Construction
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
{ A, B }
8
9. XTA
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
{ A, B }
{ A, B }
9
10. XTA
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
{ A, B }
{ A, B }
10
11. XTA
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
{ A, B }
{ A, B }
{ B }
11
12. XTA
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
{ A, B }
{ A, B }
{ B, C }
12
13. XTA
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
{ A, B }
{ A, B }
{ B, C }
6 edges
13
14. XTA
static void main(){
B b1 = new B();
A a1 = new A();
f(b1);
g(b1);
}
static void f(A a2){
a2.foo();
}
static void g(B b2){
B b3 = b2;
b3 = new C();
b3.foo();
}
class A {
void foo(){ }
}
class B extends A {
void foo(){ }
}
class C extends B {
void foo(){ }
}
class D extends B {
void foo(){ }
}
{ A, B }
{ A, B }
{ B, C }
6 edges
RA: 10 edges
CHA: 9 edges
RTA: 8 edges
0-CFA: 6 edges (different) 14
16. Removal of Dead Methods & Fields
• after call graph construction, remove unreachable
methods
- in some cases, must remove the body to preserve
dispatch behavior
• remove dead fields
• remove write-only fields
- e.g., fields initialized in constructor but never read
- also remove the write instructions
16
17. Method Call Inlining
• inline method calls if:
- XTA determines that a method call has a unique target
- inlining the call does not increase application size
17
18. Class Hierarchy Transformations
• remove uninstantiated class that does not have any subclasses
and that that does not contain any live methods or fields
• merge base class X and a derived class Y if (i) there is no live non-
abstract method f that occurs in both X and Y , and: (1) X is
uninstantiated, or (2) Y does not contain any live non-static fields.
- by requiring that (1) or (2) holds, we ensure that no object
created by the application becomes larger (i.e., contains more
fields) as a result of the merge
• similar transformations for merging classes with interfaces
18
19. Name Compression
• select short names (e.g., “a”, “b”, “c”) to classes, methods, fields
• care must be taken to preserve:
- overriding behavior
- overload resolution
19
21. Modular Extraction Language (MEL)
• specify that methods are dynamically loaded or
reflectively accessed
• support various extraction scenarios:
- extract library without assumptions about clients
- extract library in the context of a specific
application
- extract client without assumptions about libraries
21
FSE’00
23. SmartLinker - Commercial Application of Jax
• IBM J9 Virtual Machine for embedded platforms offers Japt:
- an optimization utility to reduce Java classes from a JAR file
- based directly on Jax algorithms, RTA and XTA
- focus on embedded, inlining JSR calls, AOT, JXE linking
23
BTA
AOT
Link
RTX, XTA
Inlining
flattening
Smartlinker
jax
AOT
Link
RTX, XTA, ITA
inlining
flattening
jar2jxe
japt
24. Smartlinker Use Case: Strings in Eclipse
• 50% of the heap is Strings of which 50% is unique
• String compaction can save 35% of the heap
• Combining Japt compression with memory-mapped JXEs
allows WebSphere Application Server to scale 2X
K
95K
190K
285K
380K
475K
Original Japt
Eclipse runtime.jar
26. Lessons Learned
• Debloating can offer dramatic improvements in memory consumption and startup times.
• OO design is a useful technique, providing meaningful abstractions and scalable designs.
Developers should keep using redundant class definitions, deep inheritance, verbose interfaces.
- rely on static analysis tools like Jax/SmartLinker to debloat verbose libraries & frameworks
• the debloating techniques that we applied are broadly applicable:
- applets, applications, Eclipse, WAS, embedded platforms, Android
- any OO language, e.g. Swift, C#, Objective-C, Kotlin, C++.
• Promising future work would be scenario-based modularization of applications. For mobile, startup
times are key. So, can we analyze what is needed just for startup? Another scenario would be
once-only tasks, such as registration. Each component could have its own optimization techniques
applied, for instance startup code would benefit from AOT (which costs more space on disk, but
loads a lot faster). Once-only code would not be AOT'd.
• Current work at Northeastern: debloating of applications written in dynamic languages
- use a combination of (i) unsound static/dynamic analysis and (ii) a recovery mechanism for
dynamic loading of missing functionality (subject to checks). Current focus on JavaScript.
26
27. Publications and References
• Frank Tip, Chris Laffra, Peter F. Sweeney, David Streeter: Practical Experience with an
Application Extractor for Java. OOPSLA 1999: 292-305
• Peter F. Sweeney, Frank Tip: Extracting library-based object-oriented applications. SIGSOFT
FSE 2000: 98-107
• Frank Tip, Jens Palsberg: Scalable propagation-based call graph construction algorithms.
OOPSLA 2000: 281-293
• Frank Tip, Peter F. Sweeney, Chris Laffra, Aldo Eisma, David Streeter: Practical extraction
techniques for Java. ACM Trans. Program. Lang. Syst. 24(6): 625-666 (2002)
• Frank Tip, Peter F. Sweeney, Chris Laffra: Extracting library-based Java applications. Commun.
ACM 46(8): 35-40 (2003)
• WebSphere Everyplace Custom Environment product definition at www-
01.ibm.com/software/wireless/wece/features.html, referencing Japt.
• Sean Foley: From Global to Local Escape Analysis in Java. Performance Engineering Best
Practices Conference (2008)
27