1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /*
6  * Licensed to the Apache Software Foundation (ASF) under one or more
7  * contributor license agreements.  See the NOTICE file distributed with
8  * this work for additional information regarding copyright ownership.
9  * The ASF licenses this file to You under the Apache License, Version 2.0
10  * (the "License"); you may not use this file except in compliance with
11  * the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 package com.sun.org.apache.bcel.internal.classfile;
23 
24 import java.io.DataInput;
25 import java.io.DataOutputStream;
26 import java.io.IOException;
27 import com.sun.org.apache.bcel.internal.Const;
28 
29 /**
30  * This class represents a stack map entry recording the types of
31  * local variables and the the of stack items at a given byte code offset.
32  * See CLDC specification 5.3.1.2
33  *
34  * @see     StackMap
35  * @see     StackMapType
36  */
37 public final class StackMapEntry implements Node, Cloneable
38 {
39 
40     private int frame_type;
41     private int byte_code_offset;
42     private StackMapType[] types_of_locals;
43     private StackMapType[] types_of_stack_items;
44     private ConstantPool constant_pool;
45 
46 
47     /**
48      * Construct object from input stream.
49      *
50      * @param input Input stream
51      * @throws IOException
52      */
StackMapEntry(final DataInput input, final ConstantPool constantPool)53     StackMapEntry(final DataInput input, final ConstantPool constantPool) throws IOException {
54         this(input.readByte() & 0xFF, -1, null, null, constantPool);
55 
56         if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) {
57             byte_code_offset = frame_type - Const.SAME_FRAME;
58         } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
59                    frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
60             byte_code_offset = frame_type - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
61             types_of_stack_items = new StackMapType[1];
62             types_of_stack_items[0] = new StackMapType(input, constantPool);
63         } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
64             byte_code_offset = input.readShort();
65             types_of_stack_items = new StackMapType[1];
66             types_of_stack_items[0] = new StackMapType(input, constantPool);
67         } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) {
68             byte_code_offset = input.readShort();
69         } else if (frame_type == Const.SAME_FRAME_EXTENDED) {
70             byte_code_offset = input.readShort();
71         } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) {
72             byte_code_offset = input.readShort();
73             final int number_of_locals = frame_type - 251;
74             types_of_locals = new StackMapType[number_of_locals];
75             for (int i = 0; i < number_of_locals; i++) {
76                 types_of_locals[i] = new StackMapType(input, constantPool);
77             }
78         } else if (frame_type == Const.FULL_FRAME) {
79             byte_code_offset = input.readShort();
80             final int number_of_locals = input.readShort();
81             types_of_locals = new StackMapType[number_of_locals];
82             for (int i = 0; i < number_of_locals; i++) {
83                 types_of_locals[i] = new StackMapType(input, constantPool);
84             }
85             final int number_of_stack_items = input.readShort();
86             types_of_stack_items = new StackMapType[number_of_stack_items];
87             for (int i = 0; i < number_of_stack_items; i++) {
88                 types_of_stack_items[i] = new StackMapType(input, constantPool);
89             }
90         } else {
91             /* Can't happen */
92             throw new ClassFormatException ("Invalid frame type found while parsing stack map table: " + frame_type);
93         }
94     }
95 
96     /**
97      * DO NOT USE
98      *
99      * @param byteCodeOffset
100      * @param numberOfLocals NOT USED
101      * @param typesOfLocals array of {@link StackMapType}s of locals
102      * @param numberOfStackItems NOT USED
103      * @param typesOfStackItems array ot {@link StackMapType}s of stack items
104      * @param constantPool the constant pool
105      * @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)}
106      * instead
107      */
108     @java.lang.Deprecated
StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems, final StackMapType[] typesOfStackItems, final ConstantPool constantPool)109     public StackMapEntry(final int byteCodeOffset, final int numberOfLocals,
110             final StackMapType[] typesOfLocals, final int numberOfStackItems,
111             final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
112         this.byte_code_offset = byteCodeOffset;
113         this.types_of_locals = typesOfLocals != null ? typesOfLocals : new StackMapType[0];
114         this.types_of_stack_items = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0];
115         this.constant_pool = constantPool;
116     }
117 
118     /**
119      * Create an instance
120      *
121      * @param tag the frame_type to use
122      * @param byteCodeOffset
123      * @param typesOfLocals array of {@link StackMapType}s of locals
124      * @param typesOfStackItems array ot {@link StackMapType}s of stack items
125      * @param constantPool the constant pool
126      */
StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems, final ConstantPool constantPool)127     public StackMapEntry(final int tag, final int byteCodeOffset,
128             final StackMapType[] typesOfLocals,
129             final StackMapType[] typesOfStackItems, final ConstantPool constantPool) {
130         this.frame_type = tag;
131         this.byte_code_offset = byteCodeOffset;
132         this.types_of_locals = typesOfLocals != null ? typesOfLocals : new StackMapType[0];
133         this.types_of_stack_items = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0];
134         this.constant_pool = constantPool;
135     }
136 
137 
138     /**
139      * Dump stack map entry
140      *
141      * @param file Output file stream
142      * @throws IOException
143      */
dump( final DataOutputStream file )144     public void dump( final DataOutputStream file ) throws IOException {
145         file.write(frame_type);
146         if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) {
147             // nothing to be done
148         } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
149                    frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
150             types_of_stack_items[0].dump(file);
151         } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
152             file.writeShort(byte_code_offset);
153             types_of_stack_items[0].dump(file);
154         } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) {
155             file.writeShort(byte_code_offset);
156         } else if (frame_type == Const.SAME_FRAME_EXTENDED) {
157             file.writeShort(byte_code_offset);
158         } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) {
159             file.writeShort(byte_code_offset);
160             for (final StackMapType type : types_of_locals) {
161                 type.dump(file);
162             }
163         } else if (frame_type == Const.FULL_FRAME) {
164             file.writeShort(byte_code_offset);
165             file.writeShort(types_of_locals.length);
166             for (final StackMapType type : types_of_locals) {
167                 type.dump(file);
168             }
169             file.writeShort(types_of_stack_items.length);
170             for (final StackMapType type : types_of_stack_items) {
171                 type.dump(file);
172             }
173         } else {
174             /* Can't happen */
175             throw new ClassFormatException ("Invalid Stack map table tag: " + frame_type);
176         }
177     }
178 
179 
180     /**
181      * @return String representation.
182      */
183     @Override
toString()184     public String toString() {
185         final StringBuilder buf = new StringBuilder(64);
186         buf.append("(");
187         if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) {
188             buf.append("SAME");
189         } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
190                   frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
191             buf.append("SAME_LOCALS_1_STACK");
192         } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
193             buf.append("SAME_LOCALS_1_STACK_EXTENDED");
194         } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) {
195             buf.append("CHOP ").append(String.valueOf(251-frame_type));
196         } else if (frame_type == Const.SAME_FRAME_EXTENDED) {
197             buf.append("SAME_EXTENDED");
198         } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) {
199             buf.append("APPEND ").append(String.valueOf(frame_type-251));
200         } else if (frame_type == Const.FULL_FRAME) {
201             buf.append("FULL");
202         } else {
203             buf.append("UNKNOWN (").append(frame_type).append(")");
204         }
205         buf.append(", offset delta=").append(byte_code_offset);
206         if (types_of_locals.length > 0) {
207             buf.append(", locals={");
208             for (int i = 0; i < types_of_locals.length; i++) {
209                 buf.append(types_of_locals[i]);
210                 if (i < types_of_locals.length - 1) {
211                     buf.append(", ");
212                 }
213             }
214             buf.append("}");
215         }
216         if (types_of_stack_items.length > 0) {
217             buf.append(", stack items={");
218             for (int i = 0; i < types_of_stack_items.length; i++) {
219                 buf.append(types_of_stack_items[i]);
220                 if (i < types_of_stack_items.length - 1) {
221                     buf.append(", ");
222                 }
223             }
224             buf.append("}");
225         }
226         buf.append(")");
227         return buf.toString();
228     }
229 
230 
231     /**
232      * Calculate stack map entry size
233      *
234      */
getMapEntrySize()235     int getMapEntrySize() {
236         if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) {
237             return 1;
238         } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
239                    frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
240             return 1 + (types_of_stack_items[0].hasIndex() ? 3 : 1);
241         } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) {
242             return 3 + (types_of_stack_items[0].hasIndex() ? 3 : 1);
243         } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) {
244             return 3;
245         } else if (frame_type == Const.SAME_FRAME_EXTENDED) {
246             return 3;
247         } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) {
248             int len = 3;
249             for (final StackMapType types_of_local : types_of_locals) {
250                 len += types_of_local.hasIndex() ? 3 : 1;
251             }
252             return len;
253         } else if (frame_type == Const.FULL_FRAME) {
254             int len = 7;
255             for (final StackMapType types_of_local : types_of_locals) {
256                 len += types_of_local.hasIndex() ? 3 : 1;
257             }
258             for (final StackMapType types_of_stack_item : types_of_stack_items) {
259                 len += types_of_stack_item.hasIndex() ? 3 : 1;
260             }
261             return len;
262         } else {
263             throw new RuntimeException("Invalid StackMap frame_type: " + frame_type);
264         }
265     }
266 
267 
setFrameType( final int f )268     public void setFrameType( final int f ) {
269         if (f >= Const.SAME_FRAME && f <= Const.SAME_FRAME_MAX) {
270             byte_code_offset = f - Const.SAME_FRAME;
271         } else if (f >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
272                    f <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
273             byte_code_offset = f - Const.SAME_LOCALS_1_STACK_ITEM_FRAME;
274         } else if (f == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
275         } else if (f >= Const.CHOP_FRAME && f <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
276         } else if (f == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
277         } else if (f >= Const.APPEND_FRAME && f <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
278         } else if (f == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock
279         } else {
280             throw new RuntimeException("Invalid StackMap frame_type");
281         }
282         frame_type = f;
283     }
284 
285 
getFrameType()286     public int getFrameType() {
287         return frame_type;
288     }
289 
290 
setByteCodeOffset( final int new_offset )291     public void setByteCodeOffset( final int new_offset ) {
292         if (new_offset < 0 || new_offset > 32767) {
293             throw new RuntimeException("Invalid StackMap offset: " + new_offset);
294         }
295 
296         if (frame_type >= Const.SAME_FRAME &&
297             frame_type <= Const.SAME_FRAME_MAX) {
298             if (new_offset > Const.SAME_FRAME_MAX) {
299                 frame_type = Const.SAME_FRAME_EXTENDED;
300             } else {
301                 frame_type = new_offset;
302             }
303         } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME &&
304                    frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) {
305             if (new_offset > Const.SAME_FRAME_MAX) {
306                 frame_type = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
307             } else {
308                 frame_type = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + new_offset;
309             }
310         } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
311         } else if (frame_type >= Const.CHOP_FRAME &&
312                    frame_type <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
313         } else if (frame_type == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock
314         } else if (frame_type >= Const.APPEND_FRAME &&
315                    frame_type <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock
316         } else if (frame_type == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock
317         } else {
318             throw new RuntimeException("Invalid StackMap frame_type: " + frame_type);
319         }
320         byte_code_offset = new_offset;
321     }
322 
323 
324     /**
325      * Update the distance (as an offset delta) from this StackMap
326      * entry to the next.  Note that this might cause the the
327      * frame type to change.  Note also that delta may be negative.
328      *
329      * @param delta offset delta
330      */
updateByteCodeOffset(final int delta)331     public void updateByteCodeOffset(final int delta) {
332         setByteCodeOffset(byte_code_offset + delta);
333     }
334 
335 
getByteCodeOffset()336     public int getByteCodeOffset() {
337         return byte_code_offset;
338     }
339 
340 
341     /**
342      *
343      * @deprecated since 6.0
344      */
345     @java.lang.Deprecated
setNumberOfLocals( final int n )346     public void setNumberOfLocals( final int n ) { // TODO unused
347     }
348 
349 
getNumberOfLocals()350     public int getNumberOfLocals() {
351         return types_of_locals.length;
352     }
353 
354 
setTypesOfLocals( final StackMapType[] types )355     public void setTypesOfLocals( final StackMapType[] types ) {
356         types_of_locals = types != null ? types : new StackMapType[0];
357     }
358 
359 
getTypesOfLocals()360     public StackMapType[] getTypesOfLocals() {
361         return types_of_locals;
362     }
363 
364 
365     /**
366      *
367      * @deprecated since 6.0
368      */
369     @java.lang.Deprecated
setNumberOfStackItems( final int n )370     public void setNumberOfStackItems( final int n ) { // TODO unused
371     }
372 
373 
getNumberOfStackItems()374     public int getNumberOfStackItems() {
375         return types_of_stack_items.length;
376     }
377 
378 
setTypesOfStackItems( final StackMapType[] types )379     public void setTypesOfStackItems( final StackMapType[] types ) {
380         types_of_stack_items = types != null ? types : new StackMapType[0];
381     }
382 
383 
getTypesOfStackItems()384     public StackMapType[] getTypesOfStackItems() {
385         return types_of_stack_items;
386     }
387 
388 
389     /**
390      * @return deep copy of this object
391      */
copy()392     public StackMapEntry copy() {
393         StackMapEntry e;
394         try {
395             e = (StackMapEntry) clone();
396         } catch (final CloneNotSupportedException ex) {
397             throw new Error("Clone Not Supported");
398         }
399 
400         e.types_of_locals = new StackMapType[types_of_locals.length];
401         for (int i = 0; i < types_of_locals.length; i++) {
402             e.types_of_locals[i] = types_of_locals[i].copy();
403         }
404         e.types_of_stack_items = new StackMapType[types_of_stack_items.length];
405         for (int i = 0; i < types_of_stack_items.length; i++) {
406             e.types_of_stack_items[i] = types_of_stack_items[i].copy();
407         }
408         return e;
409     }
410 
411 
412     /**
413      * Called by objects that are traversing the nodes of the tree implicitely
414      * defined by the contents of a Java class. I.e., the hierarchy of methods,
415      * fields, attributes, etc. spawns a tree of objects.
416      *
417      * @param v Visitor object
418      */
419     @Override
accept( final Visitor v )420     public void accept( final Visitor v ) {
421         v.visitStackMapEntry(this);
422     }
423 
424 
425     /**
426      * @return Constant pool used by this object.
427      */
getConstantPool()428     public ConstantPool getConstantPool() {
429         return constant_pool;
430     }
431 
432 
433     /**
434      * @param constant_pool Constant pool to be used for this object.
435      */
setConstantPool( final ConstantPool constant_pool )436     public void setConstantPool( final ConstantPool constant_pool ) {
437         this.constant_pool = constant_pool;
438     }
439 }
440