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.DataInput;
20 import java.io.DataOutputStream;
21 import java.io.IOException;
22 import java.util.Arrays;
23
24 import org.apache.bcel.Const;
25 import org.apache.bcel.util.Args;
26 import org.apache.commons.lang3.ArrayUtils;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public final class Code extends Attribute {
61
62 private int maxStack;
63 private int maxLocals;
64 private byte[] code;
65 private CodeException[] exceptionTable;
66 private Attribute[] attributes;
67
68
69
70
71
72
73
74 public Code(final Code code) {
75 this(code.getNameIndex(), code.getLength(), code.getMaxStack(), code.getMaxLocals(), code.getCode(), code.getExceptionTable(), code.getAttributes(),
76 code.getConstantPool());
77 }
78
79
80
81
82
83
84
85 Code(final int nameIndex, final int length, final DataInput file, final ConstantPool constantPool) throws IOException {
86
87 this(nameIndex, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, (CodeException[]) null, (Attribute[]) null, constantPool);
88 final int codeLength = Args.requireU4(file.readInt(), 1, "Code length attribute");
89 code = new byte[codeLength];
90 file.readFully(code);
91
92
93
94
95 final int exceptionTableLength = file.readUnsignedShort();
96 exceptionTable = new CodeException[exceptionTableLength];
97 for (int i = 0; i < exceptionTableLength; i++) {
98 exceptionTable[i] = new CodeException(file);
99 }
100
101
102
103 final int attributesCount = file.readUnsignedShort();
104 attributes = new Attribute[attributesCount];
105 for (int i = 0; i < attributesCount; i++) {
106 attributes[i] = readAttribute(file, constantPool);
107 }
108
109
110
111
112 super.setLength(length);
113 }
114
115
116
117
118
119
120
121
122
123
124
125 public Code(final int nameIndex, final int length, final int maxStack, final int maxLocals, final byte[] code, final CodeException[] exceptionTable,
126 final Attribute[] attributes, final ConstantPool constantPool) {
127 super(Const.ATTR_CODE, nameIndex, length, constantPool);
128 this.maxStack = Args.requireU2(maxStack, "maxStack");
129 this.maxLocals = Args.requireU2(maxLocals, "maxLocals");
130 this.code = ArrayUtils.nullToEmpty(code);
131 this.exceptionTable = ArrayUtils.nullToEmpty(exceptionTable, CodeException[].class);
132 Args.requireU2(this.exceptionTable.length, "exceptionTable.length");
133 this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
134 super.setLength(calculateLength());
135 }
136
137
138
139
140
141
142
143 @Override
144 public void accept(final Visitor v) {
145 v.visitCode(this);
146 }
147
148
149
150
151
152 private int calculateLength() {
153 int len = 0;
154 if (attributes != null) {
155 for (final Attribute attribute : attributes) {
156 len += attribute.getLength() + 6 ;
157 }
158 }
159 return len + getInternalLength();
160 }
161
162
163
164
165
166
167 @Override
168 public Attribute copy(final ConstantPool constantPool) {
169 final Code c = (Code) clone();
170 if (code != null) {
171 c.code = code.clone();
172 }
173 c.setConstantPool(constantPool);
174 c.exceptionTable = new CodeException[exceptionTable.length];
175 Arrays.setAll(c.exceptionTable, i -> exceptionTable[i].copy());
176 c.attributes = new Attribute[attributes.length];
177 Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
178 return c;
179 }
180
181
182
183
184
185
186
187 @Override
188 public void dump(final DataOutputStream file) throws IOException {
189 super.dump(file);
190 file.writeShort(maxStack);
191 file.writeShort(maxLocals);
192 file.writeInt(code.length);
193 file.write(code, 0, code.length);
194 file.writeShort(exceptionTable.length);
195 for (final CodeException exception : exceptionTable) {
196 exception.dump(file);
197 }
198 file.writeShort(attributes.length);
199 for (final Attribute attribute : attributes) {
200 attribute.dump(file);
201 }
202 }
203
204
205
206
207
208 public Attribute[] getAttributes() {
209 return attributes;
210 }
211
212
213
214
215 public byte[] getCode() {
216 return code;
217 }
218
219
220
221
222
223 public CodeException[] getExceptionTable() {
224 return exceptionTable;
225 }
226
227
228
229
230 private int getInternalLength() {
231 return 2 + 2 + 4
232 + code.length
233 + 2
234 + 8 * (exceptionTable == null ? 0 : exceptionTable.length)
235 + 2 ;
236 }
237
238
239
240
241 public LineNumberTable getLineNumberTable() {
242 for (final Attribute attribute : attributes) {
243 if (attribute instanceof LineNumberTable) {
244 return (LineNumberTable) attribute;
245 }
246 }
247 return null;
248 }
249
250
251
252
253 public LocalVariableTable getLocalVariableTable() {
254 for (final Attribute attribute : attributes) {
255 if (attribute instanceof LocalVariableTable) {
256 return (LocalVariableTable) attribute;
257 }
258 }
259 return null;
260 }
261
262
263
264
265
266
267 public LocalVariableTypeTable getLocalVariableTypeTable() {
268 for (final Attribute attribute : attributes) {
269 if (attribute instanceof LocalVariableTypeTable) {
270 return (LocalVariableTypeTable) attribute;
271 }
272 }
273 return null;
274 }
275
276
277
278
279 public int getMaxLocals() {
280 return maxLocals;
281 }
282
283
284
285
286 public int getMaxStack() {
287 return maxStack;
288 }
289
290
291
292
293
294
295 public StackMap getStackMap() {
296 for (final Attribute attribute : attributes) {
297 if (attribute instanceof StackMap) {
298 return (StackMap) attribute;
299 }
300 }
301 return null;
302 }
303
304
305
306
307 public void setAttributes(final Attribute[] attributes) {
308 this.attributes = attributes != null ? attributes : EMPTY_ARRAY;
309 super.setLength(calculateLength());
310 }
311
312
313
314
315 public void setCode(final byte[] code) {
316 this.code = ArrayUtils.nullToEmpty(code);
317 super.setLength(calculateLength());
318 }
319
320
321
322
323 public void setExceptionTable(final CodeException[] exceptionTable) {
324 this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_ARRAY;
325 super.setLength(calculateLength());
326 }
327
328
329
330
331 public void setMaxLocals(final int maxLocals) {
332 this.maxLocals = maxLocals;
333 }
334
335
336
337
338 public void setMaxStack(final int maxStack) {
339 this.maxStack = maxStack;
340 }
341
342
343
344
345 @Override
346 public String toString() {
347 return toString(true);
348 }
349
350
351
352
353
354
355
356 public String toString(final boolean verbose) {
357 final StringBuilder buf = new StringBuilder(100);
358 buf.append("Code(maxStack = ").append(maxStack).append(", maxLocals = ").append(maxLocals).append(", code_length = ").append(code.length).append(")\n")
359 .append(Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose));
360 if (exceptionTable.length > 0) {
361 buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n");
362 for (final CodeException exception : exceptionTable) {
363 buf.append(exception.toString(super.getConstantPool(), verbose)).append("\n");
364 }
365 }
366 if (attributes.length > 0) {
367 buf.append("\nAttribute(s) = ");
368 for (final Attribute attribute : attributes) {
369 buf.append("\n").append(attribute.getName()).append(":");
370 buf.append("\n").append(attribute);
371 }
372 }
373 return buf.toString();
374 }
375 }