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 }