1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.classfile;
18
19 import java.io.DataInputStream;
20 import java.io.DataOutputStream;
21 import java.io.IOException;
22 import org.apache.bcel.Constants;
23
24 /***
25 * This class represents a chunk of Java byte code contained in a
26 * method. It is instantiated by the
27 * <em>Attribute.readAttribute()</em> method. A <em>Code</em>
28 * attribute contains informations about operand stack, local
29 * variables, byte code and the exceptions handled within this
30 * method.
31 *
32 * This attribute has attributes itself, namely <em>LineNumberTable</em> which
33 * is used for debugging purposes and <em>LocalVariableTable</em> which
34 * contains information about the local variables.
35 *
36 * @version $Id: Code.java 386056 2006-03-15 11:31:56Z tcurdt $
37 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
38 * @see Attribute
39 * @see CodeException
40 * @see LineNumberTable
41 * @see LocalVariableTable
42 */
43 public final class Code extends Attribute {
44
45 private int max_stack;
46 private int max_locals;
47 private int code_length;
48 private byte[] code;
49 private int exception_table_length;
50 private CodeException[] exception_table;
51 private int attributes_count;
52 private Attribute[] attributes;
53
54
55 /***
56 * Initialize from another object. Note that both objects use the same
57 * references (shallow copy). Use copy() for a physical copy.
58 */
59 public Code(Code c) {
60 this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(), c.getCode(), c
61 .getExceptionTable(), c.getAttributes(), c.getConstantPool());
62 }
63
64
65 /***
66 * @param name_index Index pointing to the name <em>Code</em>
67 * @param length Content length in bytes
68 * @param file Input stream
69 * @param constant_pool Array of constants
70 */
71 Code(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
72 throws IOException {
73
74 this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null,
75 (CodeException[]) null, (Attribute[]) null, constant_pool);
76 code_length = file.readInt();
77 code = new byte[code_length];
78 file.readFully(code);
79
80
81
82 exception_table_length = file.readUnsignedShort();
83 exception_table = new CodeException[exception_table_length];
84 for (int i = 0; i < exception_table_length; i++) {
85 exception_table[i] = new CodeException(file);
86 }
87
88
89
90 attributes_count = file.readUnsignedShort();
91 attributes = new Attribute[attributes_count];
92 for (int i = 0; i < attributes_count; i++) {
93 attributes[i] = Attribute.readAttribute(file, constant_pool);
94 }
95
96
97
98
99 this.length = length;
100 }
101
102
103 /***
104 * @param name_index Index pointing to the name <em>Code</em>
105 * @param length Content length in bytes
106 * @param max_stack Maximum size of stack
107 * @param max_locals Number of local variables
108 * @param code Actual byte code
109 * @param exception_table Table of handled exceptions
110 * @param attributes Attributes of code: LineNumber or LocalVariable
111 * @param constant_pool Array of constants
112 */
113 public Code(int name_index, int length, int max_stack, int max_locals, byte[] code,
114 CodeException[] exception_table, Attribute[] attributes, ConstantPool constant_pool) {
115 super(Constants.ATTR_CODE, name_index, length, constant_pool);
116 this.max_stack = max_stack;
117 this.max_locals = max_locals;
118 setCode(code);
119 setExceptionTable(exception_table);
120 setAttributes(attributes);
121 }
122
123
124 /***
125 * Called by objects that are traversing the nodes of the tree implicitely
126 * defined by the contents of a Java class. I.e., the hierarchy of methods,
127 * fields, attributes, etc. spawns a tree of objects.
128 *
129 * @param v Visitor object
130 */
131 public void accept( Visitor v ) {
132 v.visitCode(this);
133 }
134
135
136 /***
137 * Dump code attribute to file stream in binary format.
138 *
139 * @param file Output file stream
140 * @throws IOException
141 */
142 public final void dump( DataOutputStream file ) throws IOException {
143 super.dump(file);
144 file.writeShort(max_stack);
145 file.writeShort(max_locals);
146 file.writeInt(code_length);
147 file.write(code, 0, code_length);
148 file.writeShort(exception_table_length);
149 for (int i = 0; i < exception_table_length; i++) {
150 exception_table[i].dump(file);
151 }
152 file.writeShort(attributes_count);
153 for (int i = 0; i < attributes_count; i++) {
154 attributes[i].dump(file);
155 }
156 }
157
158
159 /***
160 * @return Collection of code attributes.
161 * @see Attribute
162 */
163 public final Attribute[] getAttributes() {
164 return attributes;
165 }
166
167
168 /***
169 * @return LineNumberTable of Code, if it has one
170 */
171 public LineNumberTable getLineNumberTable() {
172 for (int i = 0; i < attributes_count; i++) {
173 if (attributes[i] instanceof LineNumberTable) {
174 return (LineNumberTable) attributes[i];
175 }
176 }
177 return null;
178 }
179
180
181 /***
182 * @return LocalVariableTable of Code, if it has one
183 */
184 public LocalVariableTable getLocalVariableTable() {
185 for (int i = 0; i < attributes_count; i++) {
186 if (attributes[i] instanceof LocalVariableTable) {
187 return (LocalVariableTable) attributes[i];
188 }
189 }
190 return null;
191 }
192
193
194 /***
195 * @return Actual byte code of the method.
196 */
197 public final byte[] getCode() {
198 return code;
199 }
200
201
202 /***
203 * @return Table of handled exceptions.
204 * @see CodeException
205 */
206 public final CodeException[] getExceptionTable() {
207 return exception_table;
208 }
209
210
211 /***
212 * @return Number of local variables.
213 */
214 public final int getMaxLocals() {
215 return max_locals;
216 }
217
218
219 /***
220 * @return Maximum size of stack used by this method.
221 */
222 public final int getMaxStack() {
223 return max_stack;
224 }
225
226
227 /***
228 * @return the internal length of this code attribute (minus the first 6 bytes)
229 * and excluding all its attributes
230 */
231 private final int getInternalLength() {
232 return 2
233 + code_length
234 + 2
235 + 8 * exception_table_length
236 + 2
237 }
238
239
240 /***
241 * @return the full size of this code attribute, minus its first 6 bytes,
242 * including the size of all its contained attributes
243 */
244 private final int calculateLength() {
245 int len = 0;
246 for (int i = 0; i < attributes_count; i++) {
247 len += attributes[i].length + 6
248 }
249 return len + getInternalLength();
250 }
251
252
253 /***
254 * @param attributes the attributes to set for this Code
255 */
256 public final void setAttributes( Attribute[] attributes ) {
257 this.attributes = attributes;
258 attributes_count = (attributes == null) ? 0 : attributes.length;
259 length = calculateLength();
260 }
261
262
263 /***
264 * @param code byte code
265 */
266 public final void setCode( byte[] code ) {
267 this.code = code;
268 code_length = (code == null) ? 0 : code.length;
269 }
270
271
272 /***
273 * @param exception_table exception table
274 */
275 public final void setExceptionTable( CodeException[] exception_table ) {
276 this.exception_table = exception_table;
277 exception_table_length = (exception_table == null) ? 0 : exception_table.length;
278 }
279
280
281 /***
282 * @param max_locals maximum number of local variables
283 */
284 public final void setMaxLocals( int max_locals ) {
285 this.max_locals = max_locals;
286 }
287
288
289 /***
290 * @param max_stack maximum stack size
291 */
292 public final void setMaxStack( int max_stack ) {
293 this.max_stack = max_stack;
294 }
295
296
297 /***
298 * @return String representation of code chunk.
299 */
300 public final String toString( boolean verbose ) {
301 StringBuffer buf;
302 buf = new StringBuffer(100);
303 buf.append("Code(max_stack = ").append(max_stack).append(", max_locals = ").append(
304 max_locals).append(", code_length = ").append(code_length).append(")\n").append(
305 Utility.codeToString(code, constant_pool, 0, -1, verbose));
306 if (exception_table_length > 0) {
307 buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
308 for (int i = 0; i < exception_table_length; i++) {
309 buf.append(exception_table[i].toString(constant_pool, verbose)).append("\n");
310 }
311 }
312 if (attributes_count > 0) {
313 buf.append("\nAttribute(s) = \n");
314 for (int i = 0; i < attributes_count; i++) {
315 buf.append(attributes[i].toString()).append("\n");
316 }
317 }
318 return buf.toString();
319 }
320
321
322 /***
323 * @return String representation of code chunk.
324 */
325 public final String toString() {
326 return toString(true);
327 }
328
329
330 /***
331 * @return deep copy of this attribute
332 *
333 * @param _constant_pool the constant pool to duplicate
334 */
335 public Attribute copy( ConstantPool _constant_pool ) {
336 Code c = (Code) clone();
337 if (code != null) {
338 c.code = new byte[code.length];
339 System.arraycopy(code, 0, c.code, 0, code.length);
340 }
341 c.constant_pool = _constant_pool;
342 c.exception_table = new CodeException[exception_table_length];
343 for (int i = 0; i < exception_table_length; i++) {
344 c.exception_table[i] = exception_table[i].copy();
345 }
346 c.attributes = new Attribute[attributes_count];
347 for (int i = 0; i < attributes_count; i++) {
348 c.attributes[i] = attributes[i].copy(_constant_pool);
349 }
350 return c;
351 }
352 }