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