/Users/lyon/j4p/src/javassist/expr/Expr.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.*; 
19   import javassist.bytecode.*; 
20   import javassist.compiler.*; 
21    
22   import java.util.LinkedList; 
23   import java.util.Iterator; 
24    
25   /** 
26    * Expression. 
27    */ 
28   public abstract class Expr implements Opcode { 
29       int currentPos; 
30       CodeIterator iterator; 
31       CtClass thisClass; 
32       MethodInfo thisMethod; 
33    
34       boolean edited; 
35       int maxLocals, maxStack; 
36    
37       static final String javaLangObject = "java.lang.Object"; 
38    
39       /** 
40        * Undocumented constructor.  Do not use; internal-use only. 
41        */ 
42       protected Expr(int pos, CodeIterator i, CtClass declaring, MethodInfo m) { 
43           currentPos = pos; 
44           iterator = i; 
45           thisClass = declaring; 
46           thisMethod = m; 
47       } 
48    
49       final ConstPool getConstPool() { 
50           return thisMethod.getConstPool(); 
51       } 
52    
53       final boolean edited() { 
54           return edited; 
55       } 
56    
57       final int locals() { 
58           return maxLocals; 
59       } 
60    
61       final int stack() { 
62           return maxStack; 
63       } 
64    
65       /** 
66        * Returns true if this method is static. 
67        */ 
68       final boolean withinStatic() { 
69           return (thisMethod.getAccessFlags() & AccessFlag.STATIC) != 0; 
70       } 
71    
72       /** 
73        * Returns the constructor or method containing the expression. 
74        */ 
75       public CtBehavior where() { 
76           MethodInfo mi = thisMethod; 
77           CtBehavior[] cb = thisClass.getDeclaredBehaviors(); 
78           for (int i = cb.length - 1; i >= 0; --i) 
79               if (cb[i].getMethodInfo() == mi) 
80                   return cb[i]; 
81    
82           throw new RuntimeException("fatal: not found"); 
83       } 
84    
85       /** 
86        * Returns the list of exceptions that the expression may throw. 
87        * This list includes both the exceptions that the try-catch statements 
88        * including the expression can catch and the exceptions that 
89        * the throws declaration allows the method to throw. 
90        */ 
91       public CtClass[] mayThrow() { 
92           ClassPool pool = thisClass.getClassPool(); 
93           ConstPool cp = thisMethod.getConstPool(); 
94           LinkedList list = new LinkedList(); 
95           try { 
96               CodeAttribute ca = thisMethod.getCodeAttribute(); 
97               ExceptionTable et = ca.getExceptionTable(); 
98               int pos = currentPos; 
99               int n = et.size(); 
100              for (int i = 0; i < n; ++i) 
101                  if (et.startPc(i) <= pos && pos < et.endPc(i)) { 
102                      int t = et.catchType(i); 
103                      if (t > 0) 
104                          try { 
105                              addClass(list, pool.get(cp.getClassInfo(t))); 
106                          } catch (NotFoundException e) { 
107                          } 
108                  } 
109          } catch (NullPointerException e) { 
110          } 
111   
112          ExceptionsAttribute ea = thisMethod.getExceptionsAttribute(); 
113          if (ea != null) { 
114              String[] exceptions = ea.getExceptions(); 
115              if (exceptions != null) { 
116                  int n = exceptions.length; 
117                  for (int i = 0; i < n; ++i) 
118                      try { 
119                          addClass(list, pool.get(exceptions[i])); 
120                      } catch (NotFoundException e) { 
121                      } 
122              } 
123          } 
124   
125          return (CtClass[]) list.toArray(new CtClass[list.size()]); 
126      } 
127   
128      private static void addClass(LinkedList list, CtClass c) { 
129          Iterator it = list.iterator(); 
130          while (it.hasNext()) 
131              if (it.next() == c) 
132                  return; 
133   
134          list.add(c); 
135      } 
136   
137      /** 
138       * Returns the index of the bytecode corresponding to the 
139       * expression. 
140       * It is the index into the byte array containing the Java bytecode 
141       * that implements the method. 
142       */ 
143      public int indexOfBytecode() { 
144          return currentPos; 
145      } 
146   
147      /** 
148       * Returns the line number of the source line containing the 
149       * expression. 
150       * 
151       * @return -1       if this information is not available. 
152       */ 
153      public int getLineNumber() { 
154          return thisMethod.getLineNumber(currentPos); 
155      } 
156   
157      /** 
158       * Returns the source file containing the expression. 
159       * 
160       * @return null     if this information is not available. 
161       */ 
162      public String getFileName() { 
163          ClassFile cf = thisClass.getClassFile2(); 
164          if (cf == null) 
165              return null; 
166          else 
167              return cf.getSourceFile(); 
168      } 
169   
170      static final boolean checkResultValue(CtClass retType, String prog) 
171              throws CannotCompileException { 
172          /* Is $_ included in the source code? 
173           */ 
174          boolean hasIt = (prog.indexOf(Javac.resultVarName) >= 0); 
175          if (!hasIt && retType != CtClass.voidType) 
176              throw new CannotCompileException( 
177                      "the resulting value is not stored in " 
178                      + Javac.resultVarName); 
179   
180          return hasIt; 
181      } 
182   
183      /* If isStaticCall is true, null is assigned to $0.  So $0 must 
184       * be declared by calling Javac.recordParams(). 
185       * 
186       * After executing this method, the current stack depth might 
187       * be less than 0. 
188       */ 
189      static final void storeStack(CtClass[] params, boolean isStaticCall, 
190                                   int regno, Bytecode bytecode) { 
191          storeStack0(0, params.length, params, regno + 1, bytecode); 
192          if (isStaticCall) 
193              bytecode.addOpcode(ACONST_NULL); 
194   
195          bytecode.addAstore(regno); 
196      } 
197   
198      private static void storeStack0(int i, int n, CtClass[] params, 
199                                      int regno, Bytecode bytecode) { 
200          if (i >= n) 
201              return; 
202          else { 
203              CtClass c = params[i]; 
204              int size; 
205              if (c instanceof CtPrimitiveType) 
206                  size = ((CtPrimitiveType) c).getDataSize(); 
207              else 
208                  size = 1; 
209   
210              storeStack0(i + 1, n, params, regno + size, bytecode); 
211              bytecode.addStore(regno, c); 
212          } 
213      } 
214   
215      protected void replace0(int pos, Bytecode bytecode, int size) 
216              throws BadBytecode { 
217          byte[] code = bytecode.get(); 
218          edited = true; 
219          int gap = code.length - size; 
220          for (int i = 0; i < size; ++i) 
221              iterator.writeByte(NOP, pos + i); 
222   
223          if (gap > 0) 
224              iterator.insertGap(pos, gap); 
225   
226          iterator.write(code, pos); 
227          iterator.insert(bytecode.getExceptionTable(), pos); 
228          maxLocals = bytecode.getMaxLocals(); 
229          maxStack = bytecode.getMaxStack(); 
230      } 
231  } 
232