/Users/lyon/j4p/src/javassist/expr/ExprEditor.java

1    /* 
2     * Javassist, a Java-bytecode translator toolkit. 
3     * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved. 
4     * 
5     * The contents of this file are subject to the Mozilla Public License Version 
6     * 1.1 (the "License"); you may not use this file except in compliance with 
7     * the License.  Alternatively, the contents of this file may be used under 
8     * the terms of the GNU Lesser General Public License Version 2.1 or later. 
9     * 
10    * Software distributed under the License is distributed on an "AS IS" basis, 
11    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
12    * for the specific language governing rights and limitations under the 
13    * License. 
14    */ 
15    
16   package javassist.expr; 
17    
18   import javassist.bytecode.*; 
19   import javassist.CtClass; 
20   import javassist.CannotCompileException; 
21    
22   /** 
23    * A translator of method bodies. 
24    * 
25    * <p>The users can define a subclass of this class to customize how to 
26    * modify a method body.  The overall architecture is similar to the 
27    * strategy pattern. 
28    * 
29    * <p>If <code>instrument()</code> is called in 
30    * <code>CtMethod</code>, the method body is scanned from the beginning 
31    * to the end. 
32    * Whenever an expression, such as a method call and a <tt>new</tt> 
33    * expression (object creation), 
34    * is found, <code>edit()</code> is called in <code>ExprEdit</code>. 
35    * <code>edit()</code> can inspect and modify the given expression. 
36    * The modification is reflected on the original method body.  If 
37    * <code>edit()</code> does nothing, the original method body is not 
38    * changed. 
39    * 
40    * <p>The following code is an example: 
41    * 
42    * <ul><pre> 
43    * CtMethod cm = ...; 
44    * cm.instrument(new ExprEditor() { 
45    *     public void edit(MethodCall m) throws CannotCompileException { 
46    *         if (m.getClassName().equals("Point")) { 
47    *             System.out.println(m.getMethodName() + " line: " 
48    *                                + m.getLineNumber()); 
49    *     } 
50    * }); 
51    * </pre></ul> 
52    * 
53    * <p>This code inspects all method calls appearing in the method represented 
54    * by <code>cm</code> and it prints the names and the line numbers of the 
55    * methods declared in class <code>Point</code>.  This code does not modify 
56    * the body of the method represented by <code>cm</code>.  If the method 
57    * body must be modified, call <code>replace()</code> 
58    * in <code>MethodCall</code>. 
59    * 
60    * @see javassist.CtClass#instrument(ExprEditor) 
61    * @see javassist.CtMethod#instrument(ExprEditor) 
62    * @see javassist.CtConstructor#instrument(ExprEditor) 
63    * @see MethodCall 
64    * @see NewExpr 
65    * @see FieldAccess 
66    * 
67    * @see javassist.CodeConverter 
68    */ 
69   public class ExprEditor { 
70       /** 
71        * Default constructor.  It does nothing. 
72        */ 
73       public ExprEditor() { 
74       } 
75    
76       static class NewOp { 
77           NewOp next; 
78           int pos; 
79           String type; 
80    
81           NewOp(NewOp n, int p, String t) { 
82               next = n; 
83               pos = p; 
84               type = t; 
85           } 
86       } 
87    
88       /** 
89        * Undocumented method.  Do not use; internal-use only. 
90        */ 
91       public boolean doit(CtClass clazz, MethodInfo minfo) 
92               throws CannotCompileException { 
93           CodeAttribute codeAttr = minfo.getCodeAttribute(); 
94           if (codeAttr == null) 
95               return false; 
96    
97           CodeIterator iterator = codeAttr.iterator(); 
98           boolean edited = false; 
99           int maxLocals = codeAttr.getMaxLocals(); 
100          int maxStack = 0; 
101   
102          NewOp newList = null; 
103          ConstPool cp = minfo.getConstPool(); 
104   
105          while (iterator.hasNext()) 
106              try { 
107                  Expr expr = null; 
108                  int pos = iterator.next(); 
109                  int c = iterator.byteAt(pos); 
110   
111                  if (c == Opcode.INVOKESTATIC || c == Opcode.INVOKEINTERFACE 
112                          || c == Opcode.INVOKEVIRTUAL) { 
113                      expr = new MethodCall(pos, iterator, clazz, minfo); 
114                      edit((MethodCall) expr); 
115                  } else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC 
116                          || c == Opcode.PUTFIELD || c == Opcode.PUTSTATIC) { 
117                      expr = new FieldAccess(pos, iterator, clazz, minfo, c); 
118                      edit((FieldAccess) expr); 
119                  } else if (c == Opcode.NEW) { 
120                      int index = iterator.u16bitAt(pos + 1); 
121                      newList = new NewOp(newList, pos, 
122                              cp.getClassInfo(index)); 
123                  } else if (c == Opcode.INVOKESPECIAL) { 
124                      if (newList != null && cp.isConstructor(newList.type, 
125                              iterator.u16bitAt(pos + 1)) > 0) { 
126                          expr = new NewExpr(pos, iterator, clazz, minfo, 
127                                  newList.type, newList.pos); 
128                          edit((NewExpr) expr); 
129                          newList = newList.next; 
130                      } else { 
131                          expr = new MethodCall(pos, iterator, clazz, minfo); 
132                          MethodCall mcall = (MethodCall) expr; 
133                          if (!mcall.getMethodName().equals( 
134                                  MethodInfo.nameInit)) 
135                              edit(mcall); 
136                      } 
137                  } else if (c == Opcode.INSTANCEOF) { 
138                      expr = new Instanceof(pos, iterator, clazz, minfo); 
139                      edit((Instanceof) expr); 
140                  } else if (c == Opcode.CHECKCAST) { 
141                      expr = new Cast(pos, iterator, clazz, minfo); 
142                      edit((Cast) expr); 
143                  } 
144   
145                  if (expr != null && expr.edited()) { 
146                      edited = true; 
147                      maxLocals = max(maxLocals, expr.locals()); 
148                      maxStack = max(maxStack, expr.stack()); 
149                  } 
150              } catch (BadBytecode e) { 
151                  throw new CannotCompileException(e); 
152              } 
153   
154          ExceptionTable et = codeAttr.getExceptionTable(); 
155          int n = et.size(); 
156          for (int i = 0; i < n; ++i) { 
157              Handler h = new Handler(et, i, iterator, clazz, minfo); 
158              edit(h); 
159              if (h.edited()) { 
160                  edited = true; 
161                  maxLocals = max(maxLocals, h.locals()); 
162                  maxStack = max(maxStack, h.stack()); 
163              } 
164          } 
165   
166          codeAttr.setMaxLocals(maxLocals); 
167          codeAttr.setMaxStack(codeAttr.getMaxStack() + maxStack); 
168          return edited; 
169      } 
170   
171      private int max(int i, int j) { 
172          return i > j ? i : j; 
173      } 
174   
175      /** 
176       * Edits a <tt>new</tt> expression (overridable). 
177       * The default implementation performs nothing. 
178       * 
179       * @param e         the <tt>new</tt> expression creating an object. 
180       */ 
181      public void edit(NewExpr e) throws CannotCompileException { 
182      } 
183   
184      /** 
185       * Edits a method call (overridable). 
186       * The default implementation performs nothing. 
187       */ 
188      public void edit(MethodCall m) throws CannotCompileException { 
189      } 
190   
191      /** 
192       * Edits a field-access expression (overridable). 
193       * Field access means both read and write. 
194       * The default implementation performs nothing. 
195       */ 
196      public void edit(FieldAccess f) throws CannotCompileException { 
197      } 
198   
199      /** 
200       * Edits an instanceof expression (overridable). 
201       * The default implementation performs nothing. 
202       */ 
203      public void edit(Instanceof i) throws CannotCompileException { 
204      } 
205   
206      /** 
207       * Edits an expression for explicit type casting (overridable). 
208       * The default implementation performs nothing. 
209       */ 
210      public void edit(Cast c) throws CannotCompileException { 
211      } 
212   
213      /** 
214       * Edits a catch clause (overridable). 
215       * The default implementation performs nothing. 
216       */ 
217      public void edit(Handler h) throws CannotCompileException { 
218      } 
219  } 
220