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