/Users/lyon/j4p/src/javassist/bytecode/MethodInfo.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.bytecode; 
17    
18   import java.io.DataInputStream; 
19   import java.io.DataOutputStream; 
20   import java.io.IOException; 
21   import java.util.Map; 
22   import java.util.List; 
23   import java.util.LinkedList; 
24    
25   import javassist.CannotCompileException; 
26    
27   /** 
28    * <code>method_info</code> structure. 
29    * 
30    * @see javassist.CtMethod#getMethodInfo() 
31    * @see javassist.CtConstructor#getMethodInfo() 
32    */ 
33   public final class MethodInfo { 
34       ConstPool constPool; 
35       int accessFlags; 
36       int name; 
37       int descriptor; 
38       LinkedList attribute;       // may be null 
39    
40       /** 
41        * The name of constructors: <code>&lt;init&gt</code>. 
42        */ 
43       public static final String nameInit = "<init>"; 
44    
45       /** 
46        * The name of class initializer (static initializer): 
47        * <code>&lt;clinit&gt</code>. 
48        */ 
49       public static final String nameClinit = "<clinit>"; 
50    
51       private MethodInfo(ConstPool cp) { 
52           constPool = cp; 
53           attribute = null; 
54       } 
55    
56       /** 
57        * Constructs a <code>method_info</code> structure. 
58        * 
59        * @param cp                a constant pool table 
60        * @param methodname        method name 
61        * @param desc              method descriptor 
62        * 
63        * @see Descriptor 
64        */ 
65       public MethodInfo(ConstPool cp, String methodname, String desc) { 
66           this(cp); 
67           accessFlags = 0; 
68           name = cp.addUtf8Info(methodname); 
69           descriptor = constPool.addUtf8Info(desc); 
70       } 
71    
72       MethodInfo(ConstPool cp, DataInputStream in) throws IOException { 
73           this(cp); 
74           read(in); 
75       } 
76    
77       /** 
78        * Constructs a copy of <code>method_info</code> structure. 
79        * Class names appearing in the source <code>method_info</code> 
80        * are renamed according to <code>classnameMap</code>. 
81        * 
82        * <p>Note: only <code>Code</code> and <code>Exceptions</code> 
83        * attributes are copied from the source.  The other attributes 
84        * are ignored. 
85        * 
86        * @param cp                a constant pool table 
87        * @param methodname        a method name 
88        * @param src               a source <code>method_info</code> 
89        * @param classnameMap      specifies pairs of replaced and substituted 
90        *                          name. 
91        * @see Descriptor 
92        */ 
93       public MethodInfo(ConstPool cp, String methodname, MethodInfo src, 
94                         Map classnameMap) throws BadBytecode { 
95           this(cp); 
96           read(src, methodname, classnameMap); 
97       } 
98    
99       /** 
100       * Returns a method name. 
101       */ 
102      public String getName() { 
103          return constPool.getUtf8Info(name); 
104      } 
105   
106      /** 
107       * Sets a method name. 
108       */ 
109      public void setName(String newName) { 
110          name = constPool.addUtf8Info(newName); 
111      } 
112   
113      /** 
114       * Returns true if this is not a constructor or a class initializer 
115       * (static initializer). 
116       */ 
117      public boolean isMethod() { 
118          String n = getName(); 
119          return !n.equals(nameInit) && !n.equals(nameClinit); 
120      } 
121   
122      /** 
123       * Returns a constant pool table used by this method. 
124       */ 
125      public ConstPool getConstPool() { 
126          return constPool; 
127      } 
128   
129      /** 
130       * Returns true if this is a constructor. 
131       */ 
132      public boolean isConstructor() { 
133          return getName().equals(nameInit); 
134      } 
135   
136      /** 
137       * Returns true if this is a class initializer (static initializer). 
138       */ 
139      public boolean isStaticInitializer() { 
140          return getName().equals(nameClinit); 
141      } 
142   
143      /** 
144       * Returns access flags. 
145       * 
146       * @see AccessFlag 
147       */ 
148      public int getAccessFlags() { 
149          return accessFlags; 
150      } 
151   
152      /** 
153       * Sets access flags. 
154       * 
155       * @see AccessFlag 
156       */ 
157      public void setAccessFlags(int acc) { 
158          accessFlags = acc; 
159      } 
160   
161      /** 
162       * Returns a method descriptor. 
163       * 
164       * @see Descriptor 
165       */ 
166      public String getDescriptor() { 
167          return constPool.getUtf8Info(descriptor); 
168      } 
169   
170      /** 
171       * Sets a method descriptor. 
172       * 
173       * @see Descriptor 
174       */ 
175      public void setDescriptor(String desc) { 
176          if (!desc.equals(getDescriptor())) 
177              descriptor = constPool.addUtf8Info(desc); 
178      } 
179   
180      /** 
181       * Returns all the attributes. 
182       * 
183       * @return a list of <code>AttributeInfo</code> objects. 
184       * @see AttributeInfo 
185       */ 
186      public List getAttributes() { 
187          if (attribute == null) 
188              attribute = new LinkedList(); 
189   
190          return attribute; 
191      } 
192   
193      /** 
194       * Returns the attribute with the specified name. 
195       * If it is not found, this method returns null. 
196       * 
197       * @param name      attribute name 
198       * @return          an <code>AttributeInfo</code> object or null. 
199       */ 
200      public AttributeInfo getAttribute(String name) { 
201          return AttributeInfo.lookup(attribute, name); 
202      } 
203   
204      /** 
205       * Appends an attribute.  If there is already an attribute with 
206       * the same name, the new one substitutes for it. 
207       */ 
208      public void addAttribute(AttributeInfo info) { 
209          if (attribute == null) 
210              attribute = new LinkedList(); 
211   
212          AttributeInfo.remove(attribute, info.getName()); 
213          attribute.add(info); 
214      } 
215   
216      /** 
217       * Returns an Exceptions attribute. 
218       * 
219       * @return          an Exceptions attribute 
220       *                  or null if it is not specified. 
221       */ 
222      public ExceptionsAttribute getExceptionsAttribute() { 
223          AttributeInfo info 
224                  = AttributeInfo.lookup(attribute, ExceptionsAttribute.class); 
225          return (ExceptionsAttribute) info; 
226      } 
227   
228      /** 
229       * Returns a Code attribute. 
230       * 
231       * @return          a Code attribute 
232       *                  or null if it is not specified. 
233       */ 
234      public CodeAttribute getCodeAttribute() { 
235          AttributeInfo info 
236                  = AttributeInfo.lookup(attribute, CodeAttribute.class); 
237          return (CodeAttribute) info; 
238      } 
239   
240      /** 
241       * Removes an Exception attribute. 
242       */ 
243      public void removeExceptionsAttribute() { 
244          AttributeInfo.remove(attribute, ExceptionsAttribute.class); 
245      } 
246   
247      /** 
248       * Adds an Exception attribute. 
249       * 
250       * <p>The added attribute must share the same constant pool table 
251       * as this <code>method_info</code> structure. 
252       */ 
253      public void setExceptionsAttribute(ExceptionsAttribute cattr) { 
254          removeExceptionsAttribute(); 
255          if (attribute == null) 
256              attribute = new LinkedList(); 
257   
258          attribute.add(cattr); 
259      } 
260   
261      /** 
262       * Removes a Code attribute. 
263       */ 
264      public void removeCodeAttribute() { 
265          AttributeInfo.remove(attribute, CodeAttribute.class); 
266      } 
267   
268      /** 
269       * Adds a Code attribute. 
270       * 
271       * <p>The added attribute must share the same constant pool table 
272       * as this <code>method_info</code> structure. 
273       */ 
274      public void setCodeAttribute(CodeAttribute cattr) { 
275          removeCodeAttribute(); 
276          if (attribute == null) 
277              attribute = new LinkedList(); 
278   
279          attribute.add(cattr); 
280      } 
281   
282      /** 
283       * Returns the line number of the source line corresponding to the 
284       * specified bytecode contained in this method. 
285       * 
286       * @param pos       the position of the bytecode (&gt;= 0). 
287       *                  an index into the code array. 
288       * @return -1       if this information is not available. 
289       */ 
290      public int getLineNumber(int pos) { 
291          CodeAttribute ca = getCodeAttribute(); 
292          if (ca == null) 
293              return -1; 
294   
295          LineNumberAttribute ainfo 
296                  = (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag); 
297          if (ainfo == null) 
298              return -1; 
299   
300          return ainfo.toLineNumber(pos); 
301      } 
302   
303      /** 
304       * Changes a super constructor called by this constructor. 
305       * 
306       * <p>This method modifies a call to <code>super()</code>, 
307       * which should be at the 
308       * head of a constructor body, so that a constructor in a different 
309       * super class is called.  This method does not change actural 
310       * parameters.  Hence the new super class must have a constructor 
311       * with the same signature as the original one. 
312       * 
313       * <p>This method should be called when the super class 
314       * of the class declaring this method is changed. 
315       * 
316       * <p>This method does not perform anything unless this 
317       * <code>MethodInfo</code> represents a constructor. 
318       * 
319       * @param superclass        the new super class 
320       */ 
321      public void setSuperclass(String superclass) throws BadBytecode { 
322          if (!isConstructor()) 
323              return; 
324   
325          CodeAttribute ca = getCodeAttribute(); 
326          byte[] code = ca.getCode(); 
327          CodeIterator iterator = ca.iterator(); 
328          int pos = iterator.skipSuperConstructor(); 
329          if (pos >= 0) {         // not this() 
330              ConstPool cp = constPool; 
331              int mref = ByteArray.readU16bit(code, pos + 1); 
332              int nt = cp.getMethodrefNameAndType(mref); 
333              int sc = cp.addClassInfo(superclass); 
334              int mref2 = cp.addMethodrefInfo(sc, nt); 
335              ByteArray.write16bit(mref2, code, pos + 1); 
336          } 
337      } 
338   
339      private void read(MethodInfo src, String methodname, Map classnames) 
340              throws BadBytecode { 
341          ConstPool destCp = constPool; 
342          accessFlags = src.accessFlags; 
343          name = destCp.addUtf8Info(methodname); 
344   
345          ConstPool srcCp = src.constPool; 
346          String desc = srcCp.getUtf8Info(src.descriptor); 
347          String desc2 = Descriptor.rename(desc, classnames); 
348          descriptor = destCp.addUtf8Info(desc2); 
349   
350          attribute = new LinkedList(); 
351          ExceptionsAttribute eattr = src.getExceptionsAttribute(); 
352          if (eattr != null) 
353              attribute.add(eattr.copy(destCp, classnames)); 
354   
355          CodeAttribute cattr = src.getCodeAttribute(); 
356          if (cattr != null) 
357              attribute.add(cattr.copy(destCp, classnames)); 
358      } 
359   
360      private void read(DataInputStream in) throws IOException { 
361          accessFlags = in.readUnsignedShort(); 
362          name = in.readUnsignedShort(); 
363          descriptor = in.readUnsignedShort(); 
364          int n = in.readUnsignedShort(); 
365          attribute = new LinkedList(); 
366          for (int i = 0; i < n; ++i) 
367              attribute.add(AttributeInfo.read(constPool, in)); 
368      } 
369   
370      void write(DataOutputStream out) throws IOException { 
371          out.writeShort(accessFlags); 
372          out.writeShort(name); 
373          out.writeShort(descriptor); 
374   
375          if (attribute == null) 
376              out.writeShort(0); 
377          else { 
378              out.writeShort(attribute.size()); 
379              AttributeInfo.writeAll(attribute, out); 
380          } 
381      } 
382  } 
383