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