1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.bcel.classfile;
21
22 import java.io.DataInput;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.util.Arrays;
26
27 import org.apache.bcel.Const;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public final class StackMapEntry implements Node, Cloneable {
50
51 static final StackMapEntry[] EMPTY_ARRAY = {};
52
53 private int frameType;
54 private int byteCodeOffset;
55 private StackMapType[] typesOfLocals;
56 private StackMapType[] typesOfStackItems;
57 private ConstantPool constantPool;
58
59
60
61
62
63
64
65 StackMapEntry(final DataInput dataInput, final ConstantPool constantPool) throws IOException {
66 this(dataInput.readByte() & 0xFF, -1, null, null, constantPool);
67
68 if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
69 byteCodeOffset = frameType - Const.SAME_FRAME;
70 } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
71 byteCodeOffset = frameType - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
72 typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
73 } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
74 byteCodeOffset = dataInput.readUnsignedShort();
75 typesOfStackItems = new StackMapType[] { new StackMapType(dataInput, constantPool) };
76 } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
77 byteCodeOffset = dataInput.readUnsignedShort();
78 } else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
79 byteCodeOffset = dataInput.readUnsignedShort();
80 final int numberOfLocals = frameType - 251;
81 typesOfLocals = new StackMapType[numberOfLocals];
82 for (int i = 0; i < numberOfLocals; i++) {
83 typesOfLocals[i] = new StackMapType(dataInput, constantPool);
84 }
85 } else if (frameType == Const.FULL_FRAME) {
86 byteCodeOffset = dataInput.readUnsignedShort();
87 final int numberOfLocals = dataInput.readUnsignedShort();
88 typesOfLocals = new StackMapType[numberOfLocals];
89 for (int i = 0; i < numberOfLocals; i++) {
90 typesOfLocals[i] = new StackMapType(dataInput, constantPool);
91 }
92 final int numberOfStackItems = dataInput.readUnsignedShort();
93 typesOfStackItems = new StackMapType[numberOfStackItems];
94 for (int i = 0; i < numberOfStackItems; i++) {
95 typesOfStackItems[i] = new StackMapType(dataInput, constantPool);
96 }
97 } else {
98
99 throw new ClassFormatException("Invalid frame type found while parsing stack map table: " + frameType);
100 }
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114 @java.lang.Deprecated
115 public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems,
116 final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
117 this.byteCodeOffset = byteCodeOffset;
118 this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
119 this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
120 this.constantPool = constantPool;
121 if (numberOfLocals < 0) {
122 throw new IllegalArgumentException("numberOfLocals < 0");
123 }
124 if (numberOfStackItems < 0) {
125 throw new IllegalArgumentException("numberOfStackItems < 0");
126 }
127 }
128
129
130
131
132
133
134
135
136
137
138 public StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems,
139 final ConstantPool constantPool) {
140 this.frameType = tag;
141 this.byteCodeOffset = byteCodeOffset;
142 this.typesOfLocals = typesOfLocals != null ? typesOfLocals : StackMapType.EMPTY_ARRAY;
143 this.typesOfStackItems = typesOfStackItems != null ? typesOfStackItems : StackMapType.EMPTY_ARRAY;
144 this.constantPool = constantPool;
145 }
146
147
148
149
150
151
152
153 @Override
154 public void accept(final Visitor v) {
155 v.visitStackMapEntry(this);
156 }
157
158
159
160
161 public StackMapEntry copy() {
162 final StackMapEntry e;
163 try {
164 e = (StackMapEntry) clone();
165 } catch (final CloneNotSupportedException ex) {
166 throw new UnsupportedOperationException("Clone Not Supported", ex);
167 }
168
169 e.typesOfLocals = new StackMapType[typesOfLocals.length];
170 Arrays.setAll(e.typesOfLocals, i -> typesOfLocals[i].copy());
171 e.typesOfStackItems = new StackMapType[typesOfStackItems.length];
172 Arrays.setAll(e.typesOfStackItems, i -> typesOfStackItems[i].copy());
173 return e;
174 }
175
176
177
178
179
180
181
182 public void dump(final DataOutputStream file) throws IOException {
183 file.write(frameType);
184 if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
185 typesOfStackItems[0].dump(file);
186 } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
187 file.writeShort(byteCodeOffset);
188 typesOfStackItems[0].dump(file);
189 } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
190 file.writeShort(byteCodeOffset);
191 } else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
192 file.writeShort(byteCodeOffset);
193 for (final StackMapType type : typesOfLocals) {
194 type.dump(file);
195 }
196 } else if (frameType == Const.FULL_FRAME) {
197 file.writeShort(byteCodeOffset);
198 file.writeShort(typesOfLocals.length);
199 for (final StackMapType type : typesOfLocals) {
200 type.dump(file);
201 }
202 file.writeShort(typesOfStackItems.length);
203 for (final StackMapType type : typesOfStackItems) {
204 type.dump(file);
205 }
206 } else if (!(frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX)) {
207
208 throw new ClassFormatException("Invalid Stack map table tag: " + frameType);
209 }
210 }
211
212 public int getByteCodeOffset() {
213 return byteCodeOffset;
214 }
215
216
217
218
219 public ConstantPool getConstantPool() {
220 return constantPool;
221 }
222
223 public int getFrameType() {
224 return frameType;
225 }
226
227
228
229
230 int getMapEntrySize() {
231 if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
232 return 1;
233 }
234 if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
235 return 1 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
236 }
237 if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
238 return 3 + (typesOfStackItems[0].hasIndex() ? 3 : 1);
239 }
240 if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX || frameType == Const.SAME_FRAME_EXTENDED) {
241 return 3;
242 }
243 if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
244 int len = 3;
245 for (final StackMapType typesOfLocal : typesOfLocals) {
246 len += typesOfLocal.hasIndex() ? 3 : 1;
247 }
248 return len;
249 }
250 if (frameType != Const.FULL_FRAME) {
251 throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
252 }
253 int len = 7;
254 for (final StackMapType typesOfLocal : typesOfLocals) {
255 len += typesOfLocal.hasIndex() ? 3 : 1;
256 }
257 for (final StackMapType typesOfStackItem : typesOfStackItems) {
258 len += typesOfStackItem.hasIndex() ? 3 : 1;
259 }
260 return len;
261 }
262
263 public int getNumberOfLocals() {
264 return typesOfLocals.length;
265 }
266
267 public int getNumberOfStackItems() {
268 return typesOfStackItems.length;
269 }
270
271 public StackMapType[] getTypesOfLocals() {
272 return typesOfLocals;
273 }
274
275 public StackMapType[] getTypesOfStackItems() {
276 return typesOfStackItems;
277 }
278
279 private boolean invalidFrameType(final int f) {
280
281 return f != Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
282 && !(f >= Const.CHOP_FRAME && f <= Const.CHOP_FRAME_MAX)
283 && f != Const.SAME_FRAME_EXTENDED
284 && !(f >= Const.APPEND_FRAME && f <= Const.APPEND_FRAME_MAX)
285 && f != Const.FULL_FRAME;
286
287 }
288
289 public void setByteCodeOffset(final int newOffset) {
290 if (newOffset < 0 || newOffset > 32767) {
291 throw new IllegalArgumentException("Invalid StackMap offset: " + newOffset);
292 }
293
294 if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
295 if (newOffset > Const.SAME_FRAME_MAX) {
296 frameType = Const.SAME_FRAME_EXTENDED;
297 } else {
298 frameType = newOffset;
299 }
300 } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
301 if (newOffset > Const.SAME_FRAME_MAX) {
302 frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
303 } else {
304 frameType = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + newOffset;
305 }
306 } else if (invalidFrameType(frameType)) {
307 throw new IllegalStateException("Invalid StackMap frameType: " + frameType);
308 }
309 byteCodeOffset = newOffset;
310 }
311
312
313
314
315 public void setConstantPool(final ConstantPool constantPool) {
316 this.constantPool = constantPool;
317 }
318
319 public void setFrameType(final int ft) {
320 if (ft >= Const.SAME_FRAME && ft <= Const.SAME_FRAME_MAX) {
321 byteCodeOffset = ft - Const.SAME_FRAME;
322 } else if (ft >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && ft <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
323 byteCodeOffset = ft - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
324 } else if (invalidFrameType(ft)) {
325 throw new IllegalArgumentException("Invalid StackMap frameType");
326 }
327 frameType = ft;
328 }
329
330
331
332
333
334 @java.lang.Deprecated
335 public void setNumberOfLocals(final int n) {
336 }
337
338
339
340
341
342 @java.lang.Deprecated
343 public void setNumberOfStackItems(final int n) {
344 }
345
346 public void setTypesOfLocals(final StackMapType[] types) {
347 typesOfLocals = types != null ? types : StackMapType.EMPTY_ARRAY;
348 }
349
350 public void setTypesOfStackItems(final StackMapType[] types) {
351 typesOfStackItems = types != null ? types : StackMapType.EMPTY_ARRAY;
352 }
353
354
355
356
357 @Override
358 public String toString() {
359 final StringBuilder buf = new StringBuilder(64);
360 buf.append("(");
361 if (frameType >= Const.SAME_FRAME && frameType <= Const.SAME_FRAME_MAX) {
362 buf.append("SAME");
363 } else if (frameType >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && frameType <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
364 buf.append("SAME_LOCALS_1_STACK");
365 } else if (frameType == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
366 buf.append("SAME_LOCALS_1_STACK_EXTENDED");
367 } else if (frameType >= Const.CHOP_FRAME && frameType <= Const.CHOP_FRAME_MAX) {
368 buf.append("CHOP ").append(String.valueOf(251 - frameType));
369 } else if (frameType == Const.SAME_FRAME_EXTENDED) {
370 buf.append("SAME_EXTENDED");
371 } else if (frameType >= Const.APPEND_FRAME && frameType <= Const.APPEND_FRAME_MAX) {
372 buf.append("APPEND ").append(String.valueOf(frameType - 251));
373 } else if (frameType == Const.FULL_FRAME) {
374 buf.append("FULL");
375 } else {
376 buf.append("UNKNOWN (").append(frameType).append(")");
377 }
378 buf.append(", offset delta=").append(byteCodeOffset);
379 if (typesOfLocals.length > 0) {
380 buf.append(", locals={");
381 for (int i = 0; i < typesOfLocals.length; i++) {
382 buf.append(typesOfLocals[i]);
383 if (i < typesOfLocals.length - 1) {
384 buf.append(", ");
385 }
386 }
387 buf.append("}");
388 }
389 if (typesOfStackItems.length > 0) {
390 buf.append(", stack items={");
391 for (int i = 0; i < typesOfStackItems.length; i++) {
392 buf.append(typesOfStackItems[i]);
393 if (i < typesOfStackItems.length - 1) {
394 buf.append(", ");
395 }
396 }
397 buf.append("}");
398 }
399 buf.append(")");
400 return buf.toString();
401 }
402
403
404
405
406
407
408
409 public void updateByteCodeOffset(final int delta) {
410 setByteCodeOffset(byteCodeOffset + delta);
411 }
412 }