/Users/lyon/j4p/src/javassist/bytecode/CodeAttribute.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.List; 
22   import java.util.LinkedList; 
23   import java.util.Map; 
24    
25   import javassist.CtClass; 
26    
27   /** 
28    * <code>Code_attribute</code>. 
29    * 
30    * <p>To browse the <code>code</code> field of 
31    * a <code>Code_attribute</code> structure, 
32    * use <code>CodeIterator</code>. 
33    * 
34    * @see CodeIterator 
35    */ 
36   public class CodeAttribute extends AttributeInfo implements Opcode { 
37       /** 
38        * The name of this attribute <code>"Code"</code>. 
39        */ 
40       public static final String tag = "Code"; 
41    
42       // code[] is stored in AttributeInfo.info. 
43    
44       private int maxStack; 
45       private int maxLocals; 
46       private ExceptionTable exceptions; 
47       private LinkedList attributes; 
48    
49       /** 
50        * Constructs a <code>Code_attribute</code>. 
51        * 
52        * @param cp        constant pool table 
53        * @param stack     <code>max_stack</code> 
54        * @param locals    <code>max_locals</code> 
55        * @param code      <code>code[]</code> 
56        * @param etable    <code>exception_table[]</code> 
57        */ 
58       public CodeAttribute(ConstPool cp, int stack, int locals, byte[] code, 
59                            ExceptionTable etable) { 
60           super(cp, tag); 
61           maxStack = stack; 
62           maxLocals = locals; 
63           info = code; 
64           exceptions = etable; 
65           attributes = new LinkedList(); 
66       } 
67    
68       /** 
69        * Constructs a copy of <code>Code_attribute</code>. 
70        * Specified class names are replaced during the copy. 
71        * 
72        * @param cp                constant pool table. 
73        * @param src               source Code attribute. 
74        * @param classnames        pairs of replaced and substituted 
75        *                          class names. 
76        */ 
77       private CodeAttribute(ConstPool cp, CodeAttribute src, Map classnames) 
78               throws BadBytecode { 
79           super(cp, tag); 
80    
81           maxStack = src.getMaxStack(); 
82           maxLocals = src.getMaxLocals(); 
83           exceptions = src.getExceptionTable().copy(cp, classnames); 
84           info = src.copyCode(cp, classnames, exceptions); 
85           attributes = new LinkedList(); 
86    
87           /* Since an index into the source constant pool table may not 
88              be translated, we don't copy the attributes. 
89           */ 
90           /* 
91           List src_attr = src.getAttributes(); 
92           int num = src_attr.size(); 
93           for (int i = 0; i < num; ++i) { 
94               AttributeInfo ai = (AttributeInfo)src_attr.get(i); 
95               attributes.add(ai.copy(cp, classnames)); 
96           } 
97           */ 
98       } 
99    
100      CodeAttribute(ConstPool cp, int name_id, DataInputStream in) 
101              throws IOException { 
102          super(cp, name_id, (byte[]) null); 
103          int attr_len = in.readInt(); 
104   
105          maxStack = in.readUnsignedShort(); 
106          maxLocals = in.readUnsignedShort(); 
107   
108          int code_len = in.readInt(); 
109          info = new byte[code_len]; 
110          in.readFully(info); 
111   
112          exceptions = new ExceptionTable(cp, in); 
113   
114          attributes = new LinkedList(); 
115          int num = in.readUnsignedShort(); 
116          for (int i = 0; i < num; ++i) 
117              attributes.add(AttributeInfo.read(cp, in)); 
118      } 
119   
120      /** 
121       * Makes a copy.  Class names are replaced according to the 
122       * given <code>Map</code> object. 
123       * 
124       * @param newCp     the constant pool table used by the new copy. 
125       * @param classnames        pairs of replaced and substituted 
126       *                          class names. 
127       * @exception RuntimeCopyException  if a <code>BadBytecode</code> 
128       *                          exception is thrown, it is 
129       *                          converted into 
130       *                          <code>RuntimeCopyException</code>. 
131       * 
132       * @return <code>CodeAttribute</code> object. 
133       */ 
134      public AttributeInfo copy(ConstPool newCp, Map classnames) 
135              throws RuntimeCopyException { 
136          try { 
137              return new CodeAttribute(newCp, this, classnames); 
138          } catch (BadBytecode e) { 
139              throw new RuntimeCopyException("bad bytecode. fatal?"); 
140          } 
141      } 
142   
143      /** 
144       * An exception that may be thrown by <code>copy()</code> 
145       * in <code>CodeAttribute</code>. 
146       */ 
147      public static class RuntimeCopyException extends RuntimeException { 
148          /** 
149           * Constructs an exception. 
150           */ 
151          public RuntimeCopyException(String s) { 
152              super(s); 
153          } 
154      } 
155   
156      /** 
157       * Returns the length of this <code>attribute_info</code> 
158       * structure. 
159       * The returned value is <code>attribute_length + 6</code>. 
160       */ 
161      public int length() { 
162          return 18 + info.length + exceptions.size() * 8 
163                  + AttributeInfo.getLength(attributes); 
164      } 
165   
166      void write(DataOutputStream out) throws IOException { 
167          out.writeShort(name);           // attribute_name_index 
168          out.writeInt(length() - 6);     // attribute_length 
169          out.writeShort(maxStack);       // max_stack 
170          out.writeShort(maxLocals);      // max_locals 
171          out.writeInt(info.length);      // code_length 
172          out.write(info);                // code 
173          exceptions.write(out); 
174          out.writeShort(attributes.size());      // attributes_count 
175          AttributeInfo.writeAll(attributes, out);        // attributes 
176      } 
177   
178      /** 
179       * This method is not available. 
180       * 
181       * @throws java.lang.UnsupportedOperationException  always thrown. 
182       */ 
183      public byte[] get() { 
184          throw new UnsupportedOperationException("CodeAttribute.get()"); 
185      } 
186   
187      /** 
188       * This method is not available. 
189       * 
190       * @throws java.lang.UnsupportedOperationException  always thrown. 
191       */ 
192      public void set(byte[] newinfo) { 
193          throw new UnsupportedOperationException("CodeAttribute.set()"); 
194      } 
195   
196      /** 
197       * Returns the name of the class declaring the method including 
198       * this code attribute. 
199       */ 
200      public String getDeclaringClass() { 
201          ConstPool cp = getConstPool(); 
202          return cp.getClassName(); 
203      } 
204   
205      /** 
206       * Returns <code>max_stack</code>. 
207       */ 
208      public int getMaxStack() { 
209          return maxStack; 
210      } 
211   
212      /** 
213       * Sets <code>max_stack</code>. 
214       */ 
215      public void setMaxStack(int value) { 
216          maxStack = value; 
217      } 
218   
219      /** 
220       * Returns <code>max_locals</code>. 
221       */ 
222      public int getMaxLocals() { 
223          return maxLocals; 
224      } 
225   
226      /** 
227       * Sets <code>max_locals</code>. 
228       */ 
229      public void setMaxLocals(int value) { 
230          maxLocals = value; 
231      } 
232   
233      /** 
234       * Returns <code>code_length</code>. 
235       */ 
236      public int getCodeLength() { 
237          return info.length; 
238      } 
239   
240      /** 
241       * Returns <code>code[]</code>. 
242       */ 
243      public byte[] getCode() { 
244          return info; 
245      } 
246   
247      /** 
248       * Sets <code>code[]</code>. 
249       */ 
250      void setCode(byte[] newinfo) { 
251          super.set(newinfo); 
252      } 
253   
254      /** 
255       * Makes a new iterator for reading this code attribute. 
256       */ 
257      public CodeIterator iterator() { 
258          return new CodeIterator(this); 
259      } 
260   
261      /** 
262       * Returns <code>exception_table[]</code>. 
263       */ 
264      public ExceptionTable getExceptionTable() { 
265          return exceptions; 
266      } 
267   
268      /** 
269       * Returns <code>attributes[]</code>. 
270       * It returns a list of <code>AttributeInfo</code>. 
271       * 
272       * @see AttributeInfo 
273       */ 
274      public List getAttributes() { 
275          return attributes; 
276      } 
277   
278      /** 
279       * Returns the attribute with the specified name. 
280       * If it is not found, this method returns null. 
281       * 
282       * @param name      attribute name 
283       * @return          an <code>AttributeInfo</code> object or null. 
284       */ 
285      public AttributeInfo getAttribute(String name) { 
286          return AttributeInfo.lookup(attributes, name); 
287      } 
288   
289      /** 
290       * Copies code. 
291       */ 
292      private byte[] copyCode(ConstPool destCp, Map classnames, 
293                              ExceptionTable etable) 
294              throws BadBytecode { 
295          int len = getCodeLength(); 
296          byte[] newCode = new byte[len]; 
297   
298          LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(), 
299                  newCode, destCp, classnames); 
300          return LdcEntry.doit(newCode, ldc, etable); 
301      } 
302   
303      private static LdcEntry copyCode(byte[] code, int beginPos, int endPos, 
304                                       ConstPool srcCp, byte[] newcode, 
305                                       ConstPool destCp, Map classnameMap) 
306              throws BadBytecode { 
307          int i2, index; 
308          LdcEntry ldcEntry = null; 
309   
310          for (int i = beginPos; i < endPos; i = i2) { 
311              i2 = CodeIterator.nextOpcode(code, i); 
312              byte c = code[i]; 
313              newcode[i] = c; 
314              switch (c & 0xff) { 
315                  case LDC_W: 
316                  case LDC2_W: 
317                  case GETSTATIC: 
318                  case PUTSTATIC: 
319                  case GETFIELD: 
320                  case PUTFIELD: 
321                  case INVOKEVIRTUAL: 
322                  case INVOKESPECIAL: 
323                  case INVOKESTATIC: 
324                  case NEW: 
325                  case ANEWARRAY: 
326                  case CHECKCAST: 
327                  case INSTANCEOF: 
328                      copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, 
329                              classnameMap); 
330                      break; 
331                  case LDC: 
332                      index = code[i + 1] & 0xff; 
333                      index = srcCp.copy(index, destCp, classnameMap); 
334                      if (index < 0x100) 
335                          newcode[i + 1] = (byte) index; 
336                      else { 
337                          LdcEntry ldc = new LdcEntry(); 
338                          ldc.where = i; 
339                          ldc.index = index; 
340                          ldc.next = ldcEntry; 
341                          ldcEntry = ldc; 
342                      } 
343                      break; 
344                  case INVOKEINTERFACE: 
345                      copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, 
346                              classnameMap); 
347                      newcode[i + 3] = code[i + 3]; 
348                      newcode[i + 4] = code[i + 4]; 
349                      break; 
350                  case MULTIANEWARRAY: 
351                      copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, 
352                              classnameMap); 
353                      newcode[i + 3] = code[i + 3]; 
354                      break; 
355                  default : 
356                      while (++i < i2) 
357                          newcode[i] = code[i]; 
358   
359                      break; 
360              } 
361          } 
362   
363          return ldcEntry; 
364      } 
365   
366      private static void copyConstPoolInfo(int i, byte[] code, ConstPool srcCp, 
367                                            byte[] newcode, ConstPool destCp, 
368                                            Map classnameMap) { 
369          int index = ((code[i] & 0xff) << 8) | (code[i + 1] & 0xff); 
370          index = srcCp.copy(index, destCp, classnameMap); 
371          newcode[i] = (byte) (index >> 8); 
372          newcode[i + 1] = (byte) index; 
373      } 
374  } 
375   
376  final class LdcEntry { 
377      LdcEntry next; 
378      int where; 
379      int index; 
380   
381      static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable) 
382              throws BadBytecode { 
383          while (ldc != null) { 
384              int where = ldc.where; 
385              code = CodeIterator.insertGap(code, where, 1, false, etable); 
386              code[where] = (byte) Opcode.LDC_W; 
387              ByteArray.write16bit(ldc.index, code, where + 1); 
388              ldc = ldc.next; 
389          } 
390   
391          return code; 
392      } 
393  } 
394