xref: /aosp_15_r20/external/javassist/sample/evolve/Evolution.java (revision f1fbf3c2ab775ce834e0af96b7a85bdc7a0eac65)
1*f1fbf3c2SXin Li package sample.evolve;
2*f1fbf3c2SXin Li 
3*f1fbf3c2SXin Li import javassist.*;
4*f1fbf3c2SXin Li 
5*f1fbf3c2SXin Li /**
6*f1fbf3c2SXin Li  * Evolution provides a set of methods for instrumenting bytecodes.
7*f1fbf3c2SXin Li  *
8*f1fbf3c2SXin Li  * For class evolution, updatable class A is renamed to B. Then an abstract
9*f1fbf3c2SXin Li  * class named A is produced as the super class of B. If the original class A
10*f1fbf3c2SXin Li  * has a public method m(), then the abstract class A has an abstract method
11*f1fbf3c2SXin Li  * m().
12*f1fbf3c2SXin Li  *
13*f1fbf3c2SXin Li  * abstract class A abstract m() _makeInstance() | class A --------> class B m()
14*f1fbf3c2SXin Li  * m()
15*f1fbf3c2SXin Li  *
16*f1fbf3c2SXin Li  * Also, all the other classes are translated so that "new A(i)" in the methods
17*f1fbf3c2SXin Li  * is replaced with "_makeInstance(i)". This makes it possible to change the
18*f1fbf3c2SXin Li  * behavior of the instantiation of the class A.
19*f1fbf3c2SXin Li  */
20*f1fbf3c2SXin Li public class Evolution implements Translator {
21*f1fbf3c2SXin Li     public final static String handlerMethod = "_makeInstance";
22*f1fbf3c2SXin Li 
23*f1fbf3c2SXin Li     public final static String latestVersionField = VersionManager.latestVersionField;
24*f1fbf3c2SXin Li 
25*f1fbf3c2SXin Li     public final static String versionManagerMethod = "initialVersion";
26*f1fbf3c2SXin Li 
27*f1fbf3c2SXin Li     private static CtMethod trapMethod;
28*f1fbf3c2SXin Li 
29*f1fbf3c2SXin Li     private static final int initialVersion = 0;
30*f1fbf3c2SXin Li 
31*f1fbf3c2SXin Li     private ClassPool pool;
32*f1fbf3c2SXin Li 
33*f1fbf3c2SXin Li     private String updatableClassName = null;
34*f1fbf3c2SXin Li 
35*f1fbf3c2SXin Li     private CtClass updatableClass = null;
36*f1fbf3c2SXin Li 
start(ClassPool _pool)37*f1fbf3c2SXin Li     public void start(ClassPool _pool) throws NotFoundException {
38*f1fbf3c2SXin Li         pool = _pool;
39*f1fbf3c2SXin Li 
40*f1fbf3c2SXin Li         // Get the definition of Sample.make() and store it into trapMethod
41*f1fbf3c2SXin Li         // for later use.
42*f1fbf3c2SXin Li         trapMethod = _pool.getMethod("sample.evolve.Sample", "make");
43*f1fbf3c2SXin Li     }
44*f1fbf3c2SXin Li 
onLoad(ClassPool _pool, String classname)45*f1fbf3c2SXin Li     public void onLoad(ClassPool _pool, String classname)
46*f1fbf3c2SXin Li             throws NotFoundException, CannotCompileException {
47*f1fbf3c2SXin Li         onLoadUpdatable(classname);
48*f1fbf3c2SXin Li 
49*f1fbf3c2SXin Li         /*
50*f1fbf3c2SXin Li          * Replaces all the occurrences of the new operator with a call to
51*f1fbf3c2SXin Li          * _makeInstance().
52*f1fbf3c2SXin Li          */
53*f1fbf3c2SXin Li         CtClass clazz = _pool.get(classname);
54*f1fbf3c2SXin Li         CtClass absClass = updatableClass;
55*f1fbf3c2SXin Li         CodeConverter converter = new CodeConverter();
56*f1fbf3c2SXin Li         converter.replaceNew(absClass, absClass, handlerMethod);
57*f1fbf3c2SXin Li         clazz.instrument(converter);
58*f1fbf3c2SXin Li     }
59*f1fbf3c2SXin Li 
onLoadUpdatable(String classname)60*f1fbf3c2SXin Li     private void onLoadUpdatable(String classname) throws NotFoundException,
61*f1fbf3c2SXin Li             CannotCompileException {
62*f1fbf3c2SXin Li         // if the class is a concrete class,
63*f1fbf3c2SXin Li         // classname is <updatableClassName>$$<version>.
64*f1fbf3c2SXin Li 
65*f1fbf3c2SXin Li         int i = classname.lastIndexOf("$$");
66*f1fbf3c2SXin Li         if (i <= 0)
67*f1fbf3c2SXin Li             return;
68*f1fbf3c2SXin Li 
69*f1fbf3c2SXin Li         String orgname = classname.substring(0, i);
70*f1fbf3c2SXin Li         if (!orgname.equals(updatableClassName))
71*f1fbf3c2SXin Li             return;
72*f1fbf3c2SXin Li 
73*f1fbf3c2SXin Li         int version;
74*f1fbf3c2SXin Li         try {
75*f1fbf3c2SXin Li             version = Integer.parseInt(classname.substring(i + 2));
76*f1fbf3c2SXin Li         }
77*f1fbf3c2SXin Li         catch (NumberFormatException e) {
78*f1fbf3c2SXin Li             throw new NotFoundException(classname, e);
79*f1fbf3c2SXin Li         }
80*f1fbf3c2SXin Li 
81*f1fbf3c2SXin Li         CtClass clazz = pool.getAndRename(orgname, classname);
82*f1fbf3c2SXin Li         makeConcreteClass(clazz, updatableClass, version);
83*f1fbf3c2SXin Li     }
84*f1fbf3c2SXin Li 
85*f1fbf3c2SXin Li     /*
86*f1fbf3c2SXin Li      * Register an updatable class.
87*f1fbf3c2SXin Li      */
makeUpdatable(String classname)88*f1fbf3c2SXin Li     public void makeUpdatable(String classname) throws NotFoundException,
89*f1fbf3c2SXin Li             CannotCompileException {
90*f1fbf3c2SXin Li         if (pool == null)
91*f1fbf3c2SXin Li             throw new RuntimeException(
92*f1fbf3c2SXin Li                     "Evolution has not been linked to ClassPool.");
93*f1fbf3c2SXin Li 
94*f1fbf3c2SXin Li         CtClass c = pool.get(classname);
95*f1fbf3c2SXin Li         updatableClassName = classname;
96*f1fbf3c2SXin Li         updatableClass = makeAbstractClass(c);
97*f1fbf3c2SXin Li     }
98*f1fbf3c2SXin Li 
99*f1fbf3c2SXin Li     /**
100*f1fbf3c2SXin Li      * Produces an abstract class.
101*f1fbf3c2SXin Li      */
makeAbstractClass(CtClass clazz)102*f1fbf3c2SXin Li     protected CtClass makeAbstractClass(CtClass clazz)
103*f1fbf3c2SXin Li             throws CannotCompileException, NotFoundException {
104*f1fbf3c2SXin Li         int i;
105*f1fbf3c2SXin Li 
106*f1fbf3c2SXin Li         CtClass absClass = pool.makeClass(clazz.getName());
107*f1fbf3c2SXin Li         absClass.setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);
108*f1fbf3c2SXin Li         absClass.setSuperclass(clazz.getSuperclass());
109*f1fbf3c2SXin Li         absClass.setInterfaces(clazz.getInterfaces());
110*f1fbf3c2SXin Li 
111*f1fbf3c2SXin Li         // absClass.inheritAllConstructors();
112*f1fbf3c2SXin Li 
113*f1fbf3c2SXin Li         CtField fld = new CtField(pool.get("java.lang.Class"),
114*f1fbf3c2SXin Li                 latestVersionField, absClass);
115*f1fbf3c2SXin Li         fld.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
116*f1fbf3c2SXin Li 
117*f1fbf3c2SXin Li         CtField.Initializer finit = CtField.Initializer.byCall(pool
118*f1fbf3c2SXin Li                 .get("sample.evolve.VersionManager"), versionManagerMethod,
119*f1fbf3c2SXin Li                 new String[] { clazz.getName() });
120*f1fbf3c2SXin Li         absClass.addField(fld, finit);
121*f1fbf3c2SXin Li 
122*f1fbf3c2SXin Li         CtField[] fs = clazz.getDeclaredFields();
123*f1fbf3c2SXin Li         for (i = 0; i < fs.length; ++i) {
124*f1fbf3c2SXin Li             CtField f = fs[i];
125*f1fbf3c2SXin Li             if (Modifier.isPublic(f.getModifiers()))
126*f1fbf3c2SXin Li                 absClass.addField(new CtField(f.getType(), f.getName(),
127*f1fbf3c2SXin Li                         absClass));
128*f1fbf3c2SXin Li         }
129*f1fbf3c2SXin Li 
130*f1fbf3c2SXin Li         CtConstructor[] cs = clazz.getDeclaredConstructors();
131*f1fbf3c2SXin Li         for (i = 0; i < cs.length; ++i) {
132*f1fbf3c2SXin Li             CtConstructor c = cs[i];
133*f1fbf3c2SXin Li             int mod = c.getModifiers();
134*f1fbf3c2SXin Li             if (Modifier.isPublic(mod)) {
135*f1fbf3c2SXin Li                 CtMethod wm = CtNewMethod.wrapped(absClass, handlerMethod, c
136*f1fbf3c2SXin Li                         .getParameterTypes(), c.getExceptionTypes(),
137*f1fbf3c2SXin Li                         trapMethod, null, absClass);
138*f1fbf3c2SXin Li                 wm.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
139*f1fbf3c2SXin Li                 absClass.addMethod(wm);
140*f1fbf3c2SXin Li             }
141*f1fbf3c2SXin Li         }
142*f1fbf3c2SXin Li 
143*f1fbf3c2SXin Li         CtMethod[] ms = clazz.getDeclaredMethods();
144*f1fbf3c2SXin Li         for (i = 0; i < ms.length; ++i) {
145*f1fbf3c2SXin Li             CtMethod m = ms[i];
146*f1fbf3c2SXin Li             int mod = m.getModifiers();
147*f1fbf3c2SXin Li             if (Modifier.isPublic(mod))
148*f1fbf3c2SXin Li                 if (Modifier.isStatic(mod))
149*f1fbf3c2SXin Li                     throw new CannotCompileException(
150*f1fbf3c2SXin Li                             "static methods are not supported.");
151*f1fbf3c2SXin Li                 else {
152*f1fbf3c2SXin Li                     CtMethod m2 = CtNewMethod.abstractMethod(m.getReturnType(),
153*f1fbf3c2SXin Li                             m.getName(), m.getParameterTypes(), m
154*f1fbf3c2SXin Li                                     .getExceptionTypes(), absClass);
155*f1fbf3c2SXin Li                     absClass.addMethod(m2);
156*f1fbf3c2SXin Li                 }
157*f1fbf3c2SXin Li         }
158*f1fbf3c2SXin Li 
159*f1fbf3c2SXin Li         return absClass;
160*f1fbf3c2SXin Li     }
161*f1fbf3c2SXin Li 
162*f1fbf3c2SXin Li     /**
163*f1fbf3c2SXin Li      * Modifies the given class file so that it is a subclass of the abstract
164*f1fbf3c2SXin Li      * class produced by makeAbstractClass().
165*f1fbf3c2SXin Li      *
166*f1fbf3c2SXin Li      * Note: the naming convention must be consistent with
167*f1fbf3c2SXin Li      * VersionManager.update().
168*f1fbf3c2SXin Li      */
makeConcreteClass(CtClass clazz, CtClass abstractClass, int version)169*f1fbf3c2SXin Li     protected void makeConcreteClass(CtClass clazz, CtClass abstractClass,
170*f1fbf3c2SXin Li             int version) throws CannotCompileException, NotFoundException {
171*f1fbf3c2SXin Li         int i;
172*f1fbf3c2SXin Li         clazz.setSuperclass(abstractClass);
173*f1fbf3c2SXin Li         CodeConverter converter = new CodeConverter();
174*f1fbf3c2SXin Li         CtField[] fs = clazz.getDeclaredFields();
175*f1fbf3c2SXin Li         for (i = 0; i < fs.length; ++i) {
176*f1fbf3c2SXin Li             CtField f = fs[i];
177*f1fbf3c2SXin Li             if (Modifier.isPublic(f.getModifiers()))
178*f1fbf3c2SXin Li                 converter.redirectFieldAccess(f, abstractClass, f.getName());
179*f1fbf3c2SXin Li         }
180*f1fbf3c2SXin Li 
181*f1fbf3c2SXin Li         CtConstructor[] cs = clazz.getDeclaredConstructors();
182*f1fbf3c2SXin Li         for (i = 0; i < cs.length; ++i)
183*f1fbf3c2SXin Li             cs[i].instrument(converter);
184*f1fbf3c2SXin Li 
185*f1fbf3c2SXin Li         CtMethod[] ms = clazz.getDeclaredMethods();
186*f1fbf3c2SXin Li         for (i = 0; i < ms.length; ++i)
187*f1fbf3c2SXin Li             ms[i].instrument(converter);
188*f1fbf3c2SXin Li     }
189*f1fbf3c2SXin Li }
190