Retroactive API Extensions Through Bytecode Weaving
description
Transcript of Retroactive API Extensions Through Bytecode Weaving
Retroactive API Extensions
Through Bytecode Weaving Jevgeni Kabanov
PhD student, University of Tartu
WHAT?API Extensions
Application programming interfaceNew APIs, changed APIs
Bytecode WeavingBytecode: stack-based Java-like language Weaving: runtime program rewriting
RetroactiveAbstraction after the factWithout access to source code
WHY?Java EE is implemented by application containers each with specific extensions
Frameworks and applications need a unified access to container-specific features
EXAMPLEJavaScript, DOM, abstraction libraries
GWTPrototypejQueryExt JS
Spring (Java framework)Abstraction over some common Java EE features for applications
BEHIND THE SCENES
MyObject.class
MyObject.classMyClass_
3MyClass’MyClass
IDEs Servers Frameworks
Open-Source API
Class loader APIpublic abstract class ClassLoader { public Class loadClass(String name); protected Class defineClass(byte[] b);
public URL getResource(String name); public Enumeration getResources(String
name);
public ClassLoader getParent()}
API ExtensionsChange loadClass() to include the classes we provide to it
Add a method getChildResources() that returns the resources hierarchically
Java Class Definition
Modifiers, name, super class, interfacesEnclosing class referenceAnnotation*Inner class* NameField* Modifiers, name, type
Annotation*Method* Modifiers, name, return and parameter types
Annotation*Compiled code
Java Execution Model
Method B
Method A
MainL0 L1 L2 L3O1 O2
L0 L1 L2O1 O2 O3
L0 L1O1
Local variables
Operand stack
Execution stackFrame
Calli
ng a
met
hod
Thro
win
g an
ex
cept
ion
Instruction Example
INVOKEINTERFACE java/util/List get (I)LObject;
opcode arguments
... java.util.List int ... java.util.List.get(int)apply
Operands stack when applying the instruction:
Instruction:
Hello, World! in Bytecodepublic class HelloWorld { public <init>()V ALOAD 0 INVOKESPECIAL Object.<init>()V RETURN public static main([LString;)V GETSTATIC System.out : LPrintStream; LDC "Hello, World!" INVOKEVIRTUAL PrintStream.println(LString;)V RETURN}
REWRITING IS EASYASM
Visitor APILow level
JavassistString-embedded Java DSL High-level, but adjustable
PROBLEM 1: TRANSPARENCYIf the result of an API call is altered, how do we access the original from our framework?
E.g. ClassLoader.loadClass()
PROBLEM 2: OPTIONALWhat if the features we want to support are optional or implemented differently among implementers?
E.g. ClassLoader.getChildResources()
PROBLEM 3: VERSIONINGWhat if we have several versions of an implementation?
NB! In Java the class files are not versioned and detecting versions may be challenging
PROBLEM 4: GLOBAL STATEWhat if implementer state dictates that calls are legal in some states and illegal in others?
E.g. ClassLoader classpath is often constructed incrementally
PROBLEM 5: SYNCHRONIZATION
What if implementer does synchronization?
Synchronized in Java is a reentrant mutexClassLoader.loadClass() is synchronized, ClassLoader.getResource() usually not
Questions?