1 |
779 |
jeremybenn |
/**
|
2 |
|
|
* ASM: a very small and fast Java bytecode manipulation framework
|
3 |
|
|
* Copyright (c) 2000-2005 INRIA, France Telecom
|
4 |
|
|
* All rights reserved.
|
5 |
|
|
*
|
6 |
|
|
* Redistribution and use in source and binary forms, with or without
|
7 |
|
|
* modification, are permitted provided that the following conditions
|
8 |
|
|
* are met:
|
9 |
|
|
* 1. Redistributions of source code must retain the above copyright
|
10 |
|
|
* notice, this list of conditions and the following disclaimer.
|
11 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
12 |
|
|
* notice, this list of conditions and the following disclaimer in the
|
13 |
|
|
* documentation and/or other materials provided with the distribution.
|
14 |
|
|
* 3. Neither the name of the copyright holders nor the names of its
|
15 |
|
|
* contributors may be used to endorse or promote products derived from
|
16 |
|
|
* this software without specific prior written permission.
|
17 |
|
|
*
|
18 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19 |
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
21 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
22 |
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
23 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
28 |
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
29 |
|
|
*/
|
30 |
|
|
package org.objectweb.asm.attrs;
|
31 |
|
|
|
32 |
|
|
import java.util.ArrayList;
|
33 |
|
|
import java.util.Collections;
|
34 |
|
|
import java.util.List;
|
35 |
|
|
|
36 |
|
|
import org.objectweb.asm.Attribute;
|
37 |
|
|
import org.objectweb.asm.ByteVector;
|
38 |
|
|
import org.objectweb.asm.ClassReader;
|
39 |
|
|
import org.objectweb.asm.ClassWriter;
|
40 |
|
|
import org.objectweb.asm.Label;
|
41 |
|
|
import org.objectweb.asm.Opcodes;
|
42 |
|
|
import org.objectweb.asm.Type;
|
43 |
|
|
|
44 |
|
|
/**
|
45 |
|
|
* The stack map attribute is used during the process of verification by
|
46 |
|
|
* typechecking (§4.11.1). <br> <br> A stack map attribute consists of zero or
|
47 |
|
|
* more stack map frames. Each stack map frame specifies (either explicitly or
|
48 |
|
|
* implicitly) a bytecode offset, the verification types (§4.11.1) for the local
|
49 |
|
|
* variables, and the verification types for the operand stack. <br> <br> The
|
50 |
|
|
* type checker deals with and manipulates the expected types of a method's
|
51 |
|
|
* local variables and operand stack. Throughout this section, a location refers
|
52 |
|
|
* to either a single local variable or to a single operand stack entry. <br>
|
53 |
|
|
* <br> We will use the terms stack frame map and type state interchangeably to
|
54 |
|
|
* describe a mapping from locations in the operand stack and local variables of
|
55 |
|
|
* a method to verification types. We will usually use the term stack frame map
|
56 |
|
|
* when such a mapping is provided in the class file, and the term type state
|
57 |
|
|
* when the mapping is inferred by the type checker. <br> <br> If a method's
|
58 |
|
|
* Code attribute does not have a StackMapTable attribute, it has an implicit
|
59 |
|
|
* stack map attribute. This implicit stack map attribute is equivalent to a
|
60 |
|
|
* StackMapTable attribute with number_of_entries equal to zero. A method's Code
|
61 |
|
|
* attribute may have at most one StackMapTable attribute, otherwise a
|
62 |
|
|
* java.lang.ClassFormatError is thrown. <br> <br> The format of the stack map
|
63 |
|
|
* in the class file is given below. In the following, if the length of the
|
64 |
|
|
* method's byte code is 65535 or less, then uoffset represents the type u2;
|
65 |
|
|
* otherwise uoffset represents the type u4. If the maximum number of local
|
66 |
|
|
* variables for the method is 65535 or less, then <code>ulocalvar</code>
|
67 |
|
|
* represents the type u2; otherwise ulocalvar represents the type u4. If the
|
68 |
|
|
* maximum size of the operand stack is 65535 or less, then <code>ustack</code>
|
69 |
|
|
* represents the type u2; otherwise ustack represents the type u4.
|
70 |
|
|
*
|
71 |
|
|
* <pre>
|
72 |
|
|
* stack_map { // attribute StackMapTable
|
73 |
|
|
* u2 attribute_name_index;
|
74 |
|
|
* u4 attribute_length
|
75 |
|
|
* uoffset number_of_entries;
|
76 |
|
|
* stack_map_frame entries[number_of_entries];
|
77 |
|
|
* }
|
78 |
|
|
* </pre>
|
79 |
|
|
*
|
80 |
|
|
* Each stack_map_frame structure specifies the type state at a particular byte
|
81 |
|
|
* code offset. Each frame type specifies (explicitly or implicitly) a value,
|
82 |
|
|
* offset_delta, that is used to calulate the actual byte code offset at which
|
83 |
|
|
* it applies. The byte code offset at which the frame applies is given by
|
84 |
|
|
* adding <code>1 + offset_delta</code> to the <code>offset</code> of the
|
85 |
|
|
* previous frame, unless the previous frame is the initial frame of the method,
|
86 |
|
|
* in which case the byte code offset is <code>offset_delta</code>. <br> <br>
|
87 |
|
|
* <i>Note that the length of the byte codes is not the same as the length of
|
88 |
|
|
* the Code attribute. The byte codes are embedded in the Code attribute, along
|
89 |
|
|
* with other information.</i> <br> <br> By using an offset delta rather than
|
90 |
|
|
* the actual byte code offset we ensure, by definition, that stack map frames
|
91 |
|
|
* are in the correctly sorted order. Furthermore, by consistently using the
|
92 |
|
|
* formula <code>offset_delta + 1</code> for all explicit frames, we guarantee
|
93 |
|
|
* the absence of duplicates. <br> <br> All frame types, even full_frame, rely
|
94 |
|
|
* on the previous frame for some of their semantics. This raises the question
|
95 |
|
|
* of what is the very first frame? The initial frame is implicit, and computed
|
96 |
|
|
* from the method descriptor. See the Prolog code for methodInitialStacFrame.
|
97 |
|
|
* <br> <br> The stack_map_frame structure consists of a one-byte tag followed
|
98 |
|
|
* by zero or more bytes, giving more information, depending upon the tag. <br>
|
99 |
|
|
* <br> A stack map frame may belong to one of several frame types
|
100 |
|
|
*
|
101 |
|
|
* <pre>
|
102 |
|
|
* union stack_map_frame {
|
103 |
|
|
* same_frame;
|
104 |
|
|
* same_locals_1_stack_item_frame;
|
105 |
|
|
* chop_frame;
|
106 |
|
|
* same_frame_extended;
|
107 |
|
|
* append_frame;
|
108 |
|
|
* full_frame;
|
109 |
|
|
* }
|
110 |
|
|
* </pre>
|
111 |
|
|
*
|
112 |
|
|
* The frame type same_frame is represented by tags in the range [0-63]. If the
|
113 |
|
|
* frame type is same_frame, it means the frame has exactly the same locals as
|
114 |
|
|
* the previous stack map frame and that the number of stack items is zero. The
|
115 |
|
|
* offset_delta value for the frame is the value of the tag field, frame_type.
|
116 |
|
|
* The form of such a frame is then:
|
117 |
|
|
*
|
118 |
|
|
* <pre>
|
119 |
|
|
* same_frame {
|
120 |
|
|
* u1 frame_type = SAME; // 0-63
|
121 |
|
|
* }
|
122 |
|
|
* </pre>
|
123 |
|
|
*
|
124 |
|
|
* The frame type same_locals_1_stack_item_frame is represented by tags in the
|
125 |
|
|
* range [64, 127]. If the frame_type is same_locals_1_stack_item_frame, it
|
126 |
|
|
* means the frame has exactly the same locals as the previous stack map frame
|
127 |
|
|
* and that the number of stack items is 1. The offset_delta value for the frame
|
128 |
|
|
* is the value (frame_type - 64). There is a verification_type_info following
|
129 |
|
|
* the frame_type for the one stack item. The form of such a frame is then:
|
130 |
|
|
*
|
131 |
|
|
* <pre>
|
132 |
|
|
* same_locals_1_stack_item_frame {
|
133 |
|
|
* u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127
|
134 |
|
|
* verification_type_info stack[1];
|
135 |
|
|
* }
|
136 |
|
|
* </pre>
|
137 |
|
|
*
|
138 |
|
|
* Tags in the range [128-247] are reserved for future use. <br> <br> The frame
|
139 |
|
|
* type chop_frame is represented by tags in the range [248-250]. If the
|
140 |
|
|
* frame_type is chop_frame, it means that the current locals are the same as
|
141 |
|
|
* the locals in the previous frame, except that the k last locals are absent.
|
142 |
|
|
* The value of k is given by the formula 251-frame_type. <br> <br> The form of
|
143 |
|
|
* such a frame is then:
|
144 |
|
|
*
|
145 |
|
|
* <pre>
|
146 |
|
|
* chop_frame {
|
147 |
|
|
* u1 frame_type=CHOP; // 248-250
|
148 |
|
|
* uoffset offset_delta;
|
149 |
|
|
* }
|
150 |
|
|
* </pre>
|
151 |
|
|
*
|
152 |
|
|
* The frame type same_frame_extended is represented by the tag value 251. If
|
153 |
|
|
* the frame type is same_frame_extended, it means the frame has exactly the
|
154 |
|
|
* same locals as the previous stack map frame and that the number of stack
|
155 |
|
|
* items is zero. The form of such a frame is then:
|
156 |
|
|
*
|
157 |
|
|
* <pre>
|
158 |
|
|
* same_frame_extended {
|
159 |
|
|
* u1 frame_type = SAME_FRAME_EXTENDED; // 251
|
160 |
|
|
* uoffset offset_delta;
|
161 |
|
|
* }
|
162 |
|
|
* </pre>
|
163 |
|
|
*
|
164 |
|
|
* The frame type append_frame is represented by tags in the range [252-254]. If
|
165 |
|
|
* the frame_type is append_frame, it means that the current locals are the same
|
166 |
|
|
* as the locals in the previous frame, except that k additional locals are
|
167 |
|
|
* defined. The value of k is given by the formula frame_type-251. <br> <br> The
|
168 |
|
|
* form of such a frame is then:
|
169 |
|
|
*
|
170 |
|
|
* <pre>
|
171 |
|
|
* append_frame {
|
172 |
|
|
* u1 frame_type =APPEND; // 252-254
|
173 |
|
|
* uoffset offset_delta;
|
174 |
|
|
* verification_type_info locals[frame_type -251];
|
175 |
|
|
* }
|
176 |
|
|
* </pre>
|
177 |
|
|
*
|
178 |
|
|
* The 0th entry in locals represents the type of the first additional local
|
179 |
|
|
* variable. If locals[M] represents local variable N, then locals[M+1]
|
180 |
|
|
* represents local variable N+1 if locals[M] is one of Top_variable_info,
|
181 |
|
|
* Integer_variable_info, Float_variable_info, Null_variable_info,
|
182 |
|
|
* UninitializedThis_variable_info, Object_variable_info, or
|
183 |
|
|
* Uninitialized_variable_info, otherwise locals[M+1] represents local variable
|
184 |
|
|
* N+2. It is an error if, for any index i, locals[i] represents a local
|
185 |
|
|
* variable whose index is greater than the maximum number of local variables
|
186 |
|
|
* for the method. <br> <br> The frame type full_frame is represented by the tag
|
187 |
|
|
* value 255. The form of such a frame is then:
|
188 |
|
|
*
|
189 |
|
|
* <pre>
|
190 |
|
|
* full_frame {
|
191 |
|
|
* u1 frame_type = FULL_FRAME; // 255
|
192 |
|
|
* uoffset offset_delta;
|
193 |
|
|
* ulocalvar number_of_locals;
|
194 |
|
|
* verification_type_info locals[number_of_locals];
|
195 |
|
|
* ustack number_of_stack_items;
|
196 |
|
|
* verification_type_info stack[number_of_stack_items];
|
197 |
|
|
* }
|
198 |
|
|
* </pre>
|
199 |
|
|
*
|
200 |
|
|
* The 0th entry in locals represents the type of local variable 0. If locals[M]
|
201 |
|
|
* represents local variable N, then locals[M+1] represents local variable N+1
|
202 |
|
|
* if locals[M] is one of Top_variable_info, Integer_variable_info,
|
203 |
|
|
* Float_variable_info, Null_variable_info, UninitializedThis_variable_info,
|
204 |
|
|
* Object_variable_info, or Uninitialized_variable_info, otherwise locals[M+1]
|
205 |
|
|
* represents local variable N+2. It is an error if, for any index i, locals[i]
|
206 |
|
|
* represents a local variable whose index is greater than the maximum number of
|
207 |
|
|
* local variables for the method. <br> <br> The 0th entry in stack represents
|
208 |
|
|
* the type of the bottom of the stack, and subsequent entries represent types
|
209 |
|
|
* of stack elements closer to the top of the operand stack. We shall refer to
|
210 |
|
|
* the bottom element of the stack as stack element 0, and to subsequent
|
211 |
|
|
* elements as stack element 1, 2 etc. If stack[M] represents stack element N,
|
212 |
|
|
* then stack[M+1] represents stack element N+1 if stack[M] is one of
|
213 |
|
|
* Top_variable_info, Integer_variable_info, Float_variable_info,
|
214 |
|
|
* Null_variable_info, UninitializedThis_variable_info, Object_variable_info, or
|
215 |
|
|
* Uninitialized_variable_info, otherwise stack[M+1] represents stack element
|
216 |
|
|
* N+2. It is an error if, for any index i, stack[i] represents a stack entry
|
217 |
|
|
* whose index is greater than the maximum operand stack size for the method.
|
218 |
|
|
* <br> <br> We say that an instruction in the byte code has a corresponding
|
219 |
|
|
* stack map frame if the offset in the offset field of the stack map frame is
|
220 |
|
|
* the same as the offset of the instruction in the byte codes. <br> <br> The
|
221 |
|
|
* verification_type_info structure consists of a one-byte tag followed by zero
|
222 |
|
|
* or more bytes, giving more information about the tag. Each
|
223 |
|
|
* verification_type_info structure specifies the verification type of one or
|
224 |
|
|
* two locations.
|
225 |
|
|
*
|
226 |
|
|
* <pre>
|
227 |
|
|
* union verification_type_info {
|
228 |
|
|
* Top_variable_info;
|
229 |
|
|
* Integer_variable_info;
|
230 |
|
|
* Float_variable_info;
|
231 |
|
|
* Long_variable_info;
|
232 |
|
|
* Double_variable_info;
|
233 |
|
|
* Null_variable_info;
|
234 |
|
|
* UninitializedThis_variable_info;
|
235 |
|
|
* Object_variable_info;
|
236 |
|
|
* Uninitialized_variable_info;
|
237 |
|
|
* }
|
238 |
|
|
* </pre>
|
239 |
|
|
*
|
240 |
|
|
* The Top_variable_info type indicates that the local variable has the
|
241 |
|
|
* verification type top (T.)
|
242 |
|
|
*
|
243 |
|
|
* <pre>
|
244 |
|
|
* Top_variable_info {
|
245 |
|
|
* u1 tag = ITEM_Top; // 0
|
246 |
|
|
* }
|
247 |
|
|
* </pre>
|
248 |
|
|
*
|
249 |
|
|
* The Integer_variable_info type indicates that the location contains the
|
250 |
|
|
* verification type int.
|
251 |
|
|
*
|
252 |
|
|
* <pre>
|
253 |
|
|
* Integer_variable_info {
|
254 |
|
|
* u1 tag = ITEM_Integer; // 1
|
255 |
|
|
* }
|
256 |
|
|
* </pre>
|
257 |
|
|
*
|
258 |
|
|
* The Float_variable_info type indicates that the location contains the
|
259 |
|
|
* verification type float.
|
260 |
|
|
*
|
261 |
|
|
* <pre>
|
262 |
|
|
* Float_variable_info {
|
263 |
|
|
* u1 tag = ITEM_Float; // 2
|
264 |
|
|
* }
|
265 |
|
|
* </pre>
|
266 |
|
|
*
|
267 |
|
|
* The Long_variable_info type indicates that the location contains the
|
268 |
|
|
* verification type long. If the location is a local variable, then:
|
269 |
|
|
*
|
270 |
|
|
* <ul> <li>It must not be the local variable with the highest index.</li>
|
271 |
|
|
* <li>The next higher numbered local variable contains the verification type
|
272 |
|
|
* T.</li> </ul>
|
273 |
|
|
*
|
274 |
|
|
* If the location is an operand stack entry, then:
|
275 |
|
|
*
|
276 |
|
|
* <ul> <li>The current location must not be the topmost location of the
|
277 |
|
|
* operand stack.</li> <li>the next location closer to the top of the operand
|
278 |
|
|
* stack contains the verification type T.</li> </ul>
|
279 |
|
|
*
|
280 |
|
|
* This structure gives the contents of two locations in the operand stack or in
|
281 |
|
|
* the local variables.
|
282 |
|
|
*
|
283 |
|
|
* <pre>
|
284 |
|
|
* Long_variable_info {
|
285 |
|
|
* u1 tag = ITEM_Long; // 4
|
286 |
|
|
* }
|
287 |
|
|
* </pre>
|
288 |
|
|
*
|
289 |
|
|
* The Double_variable_info type indicates that the location contains the
|
290 |
|
|
* verification type double. If the location is a local variable, then:
|
291 |
|
|
*
|
292 |
|
|
* <ul> <li>It must not be the local variable with the highest index.</li>
|
293 |
|
|
* <li>The next higher numbered local variable contains the verification type
|
294 |
|
|
* T. <li> </ul>
|
295 |
|
|
*
|
296 |
|
|
* If the location is an operand stack entry, then:
|
297 |
|
|
*
|
298 |
|
|
* <ul> <li>The current location must not be the topmost location of the
|
299 |
|
|
* operand stack.</li> <li>the next location closer to the top of the operand
|
300 |
|
|
* stack contains the verification type T.</li> </ul>
|
301 |
|
|
*
|
302 |
|
|
* This structure gives the contents of two locations in in the operand stack or
|
303 |
|
|
* in the local variables.
|
304 |
|
|
*
|
305 |
|
|
* <pre>
|
306 |
|
|
* Double_variable_info {
|
307 |
|
|
* u1 tag = ITEM_Double; // 3
|
308 |
|
|
* }
|
309 |
|
|
* </pre>
|
310 |
|
|
*
|
311 |
|
|
* The Null_variable_info type indicates that location contains the verification
|
312 |
|
|
* type null.
|
313 |
|
|
*
|
314 |
|
|
* <pre>
|
315 |
|
|
* Null_variable_info {
|
316 |
|
|
* u1 tag = ITEM_Null; // 5
|
317 |
|
|
* }
|
318 |
|
|
* </pre>
|
319 |
|
|
*
|
320 |
|
|
* The UninitializedThis_variable_info type indicates that the location contains
|
321 |
|
|
* the verification type uninitializedThis.
|
322 |
|
|
*
|
323 |
|
|
* <pre>
|
324 |
|
|
* UninitializedThis_variable_info {
|
325 |
|
|
* u1 tag = ITEM_UninitializedThis; // 6
|
326 |
|
|
* }
|
327 |
|
|
* </pre>
|
328 |
|
|
*
|
329 |
|
|
* The Object_variable_info type indicates that the location contains an
|
330 |
|
|
* instance of the class referenced by the constant pool entry.
|
331 |
|
|
*
|
332 |
|
|
* <pre>
|
333 |
|
|
* Object_variable_info {
|
334 |
|
|
* u1 tag = ITEM_Object; // 7
|
335 |
|
|
* u2 cpool_index;
|
336 |
|
|
* }
|
337 |
|
|
* </pre>
|
338 |
|
|
*
|
339 |
|
|
* The Uninitialized_variable_info indicates that the location contains the
|
340 |
|
|
* verification type uninitialized(offset). The offset item indicates the offset
|
341 |
|
|
* of the new instruction that created the object being stored in the location.
|
342 |
|
|
*
|
343 |
|
|
* <pre>
|
344 |
|
|
* Uninitialized_variable_info {
|
345 |
|
|
* u1 tag = ITEM_Uninitialized // 8
|
346 |
|
|
* uoffset offset;
|
347 |
|
|
* }
|
348 |
|
|
* </pre>
|
349 |
|
|
*
|
350 |
|
|
* @see "ClassFileFormat-Java6.fm Page 138 Friday, April 15, 2005 3:22 PM"
|
351 |
|
|
*
|
352 |
|
|
* @author Eugene Kuleshov
|
353 |
|
|
*/
|
354 |
|
|
public class StackMapTableAttribute extends Attribute {
|
355 |
|
|
/**
|
356 |
|
|
* Frame has exactly the same locals as the previous stack map frame and
|
357 |
|
|
* number of stack items is zero.
|
358 |
|
|
*/
|
359 |
|
|
public static final int SAME_FRAME = 0; // to 63 (0-3f)
|
360 |
|
|
|
361 |
|
|
/**
|
362 |
|
|
* Frame has exactly the same locals as the previous stack map frame and
|
363 |
|
|
* number of stack items is 1
|
364 |
|
|
*/
|
365 |
|
|
public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127
|
366 |
|
|
|
367 |
|
|
// (40-7f)
|
368 |
|
|
|
369 |
|
|
/**
|
370 |
|
|
* Reserved for future use
|
371 |
|
|
*/
|
372 |
|
|
public static final int RESERVED = 128;
|
373 |
|
|
|
374 |
|
|
/**
|
375 |
|
|
* Frame has exactly the same locals as the previous stack map frame and
|
376 |
|
|
* number of stack items is 1. Offset is bigger then 63;
|
377 |
|
|
*/
|
378 |
|
|
public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
|
379 |
|
|
|
380 |
|
|
/**
|
381 |
|
|
* Frame where current locals are the same as the locals in the previous
|
382 |
|
|
* frame, except that the k last locals are absent. The value of k is given
|
383 |
|
|
* by the formula 251-frame_type.
|
384 |
|
|
*/
|
385 |
|
|
public static final int CHOP_FRAME = 248; // to 250 (f8-fA)
|
386 |
|
|
|
387 |
|
|
/**
|
388 |
|
|
* Frame has exactly the same locals as the previous stack map frame and
|
389 |
|
|
* number of stack items is zero. Offset is bigger then 63;
|
390 |
|
|
*/
|
391 |
|
|
public static final int SAME_FRAME_EXTENDED = 251; // fb
|
392 |
|
|
|
393 |
|
|
/**
|
394 |
|
|
* Frame where current locals are the same as the locals in the previous
|
395 |
|
|
* frame, except that k additional locals are defined. The value of k is
|
396 |
|
|
* given by the formula frame_type-251.
|
397 |
|
|
*/
|
398 |
|
|
public static final int APPEND_FRAME = 252; // to 254 // fc-fe
|
399 |
|
|
|
400 |
|
|
/**
|
401 |
|
|
* Full frame
|
402 |
|
|
*/
|
403 |
|
|
public static final int FULL_FRAME = 255; // ff
|
404 |
|
|
|
405 |
|
|
private static final int MAX_SHORT = 65535;
|
406 |
|
|
|
407 |
|
|
/**
|
408 |
|
|
* A <code>List</code> of <code>StackMapFrame</code> instances.
|
409 |
|
|
*/
|
410 |
|
|
private List frames;
|
411 |
|
|
|
412 |
|
|
public StackMapTableAttribute() {
|
413 |
|
|
super("StackMapTable");
|
414 |
|
|
}
|
415 |
|
|
|
416 |
|
|
public StackMapTableAttribute(List frames) {
|
417 |
|
|
this();
|
418 |
|
|
this.frames = frames;
|
419 |
|
|
}
|
420 |
|
|
|
421 |
|
|
public List getFrames() {
|
422 |
|
|
return frames;
|
423 |
|
|
}
|
424 |
|
|
|
425 |
|
|
public StackMapFrame getFrame(Label label) {
|
426 |
|
|
for (int i = 0; i < frames.size(); i++) {
|
427 |
|
|
StackMapFrame frame = (StackMapFrame) frames.get(i);
|
428 |
|
|
if (frame.label == label) {
|
429 |
|
|
return frame;
|
430 |
|
|
}
|
431 |
|
|
}
|
432 |
|
|
return null;
|
433 |
|
|
}
|
434 |
|
|
|
435 |
|
|
public boolean isUnknown() {
|
436 |
|
|
return false;
|
437 |
|
|
}
|
438 |
|
|
|
439 |
|
|
public boolean isCodeAttribute() {
|
440 |
|
|
return true;
|
441 |
|
|
}
|
442 |
|
|
|
443 |
|
|
protected Attribute read(
|
444 |
|
|
ClassReader cr,
|
445 |
|
|
int off,
|
446 |
|
|
int len,
|
447 |
|
|
char[] buf,
|
448 |
|
|
int codeOff,
|
449 |
|
|
Label[] labels)
|
450 |
|
|
{
|
451 |
|
|
|
452 |
|
|
ArrayList frames = new ArrayList();
|
453 |
|
|
|
454 |
|
|
// note that this is not the size of Code attribute
|
455 |
|
|
boolean isExtCodeSize = cr.readInt(codeOff + 4) > MAX_SHORT;
|
456 |
|
|
boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > MAX_SHORT;
|
457 |
|
|
boolean isExtStack = cr.readUnsignedShort(codeOff) > MAX_SHORT;
|
458 |
|
|
|
459 |
|
|
int offset = 0;
|
460 |
|
|
|
461 |
|
|
int methodOff = getMethodOff(cr, codeOff, buf);
|
462 |
|
|
StackMapFrame frame = new StackMapFrame(getLabel(offset, labels),
|
463 |
|
|
calculateLocals(cr.readClass(cr.header + 2, buf), // owner
|
464 |
|
|
cr.readUnsignedShort(methodOff), // method access
|
465 |
|
|
cr.readUTF8(methodOff + 2, buf), // method name
|
466 |
|
|
cr.readUTF8(methodOff + 4, buf)), // method desc
|
467 |
|
|
Collections.EMPTY_LIST);
|
468 |
|
|
frames.add(frame);
|
469 |
|
|
|
470 |
|
|
// System.err.println( cr.readUTF8( methodOff + 2, buf));
|
471 |
|
|
// System.err.println( offset +" delta:" + 0 +" : "+ frame);
|
472 |
|
|
|
473 |
|
|
int size;
|
474 |
|
|
if (isExtCodeSize) {
|
475 |
|
|
size = cr.readInt(off);
|
476 |
|
|
off += 4;
|
477 |
|
|
} else {
|
478 |
|
|
size = cr.readUnsignedShort(off);
|
479 |
|
|
off += 2;
|
480 |
|
|
}
|
481 |
|
|
|
482 |
|
|
for (; size > 0; size--) {
|
483 |
|
|
int tag = cr.readByte(off); // & 0xff;
|
484 |
|
|
off++;
|
485 |
|
|
|
486 |
|
|
List stack;
|
487 |
|
|
List locals;
|
488 |
|
|
|
489 |
|
|
int offsetDelta;
|
490 |
|
|
if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) { // SAME_FRAME
|
491 |
|
|
offsetDelta = tag;
|
492 |
|
|
|
493 |
|
|
locals = new ArrayList(frame.locals);
|
494 |
|
|
stack = Collections.EMPTY_LIST;
|
495 |
|
|
|
496 |
|
|
} else if (tag < RESERVED) { // SAME_LOCALS_1_STACK_ITEM_FRAME
|
497 |
|
|
offsetDelta = tag - SAME_LOCALS_1_STACK_ITEM_FRAME;
|
498 |
|
|
|
499 |
|
|
locals = new ArrayList(frame.locals);
|
500 |
|
|
stack = new ArrayList();
|
501 |
|
|
// read verification_type_info stack[1];
|
502 |
|
|
off = readType(stack, isExtCodeSize, cr, off, labels, buf);
|
503 |
|
|
|
504 |
|
|
} else {
|
505 |
|
|
if (isExtCodeSize) {
|
506 |
|
|
offsetDelta = cr.readInt(off);
|
507 |
|
|
off += 4;
|
508 |
|
|
} else {
|
509 |
|
|
offsetDelta = cr.readUnsignedShort(off);
|
510 |
|
|
off += 2;
|
511 |
|
|
}
|
512 |
|
|
|
513 |
|
|
if (tag == SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
|
514 |
|
|
locals = new ArrayList(frame.locals);
|
515 |
|
|
stack = new ArrayList();
|
516 |
|
|
// read verification_type_info stack[1];
|
517 |
|
|
off = readType(stack, isExtCodeSize, cr, off, labels, buf);
|
518 |
|
|
|
519 |
|
|
} else if (tag >= CHOP_FRAME && tag < SAME_FRAME_EXTENDED) { // CHOP_FRAME
|
520 |
|
|
stack = Collections.EMPTY_LIST;
|
521 |
|
|
|
522 |
|
|
int k = SAME_FRAME_EXTENDED - tag;
|
523 |
|
|
// copy locals from prev frame and chop last k
|
524 |
|
|
locals = new ArrayList(frame.locals.subList(0,
|
525 |
|
|
frame.locals.size() - k));
|
526 |
|
|
|
527 |
|
|
} else if (tag == SAME_FRAME_EXTENDED) { // SAME_FRAME_EXTENDED
|
528 |
|
|
stack = Collections.EMPTY_LIST;
|
529 |
|
|
locals = new ArrayList(frame.locals);
|
530 |
|
|
|
531 |
|
|
} else if ( /* tag>=APPEND && */tag < FULL_FRAME) { // APPEND_FRAME
|
532 |
|
|
stack = Collections.EMPTY_LIST;
|
533 |
|
|
|
534 |
|
|
// copy locals from prev frame and append new k
|
535 |
|
|
locals = new ArrayList(frame.locals);
|
536 |
|
|
for (int k = tag - SAME_FRAME_EXTENDED; k > 0; k--) {
|
537 |
|
|
off = readType(locals,
|
538 |
|
|
isExtCodeSize,
|
539 |
|
|
cr,
|
540 |
|
|
off,
|
541 |
|
|
labels,
|
542 |
|
|
buf);
|
543 |
|
|
}
|
544 |
|
|
|
545 |
|
|
} else if (tag == FULL_FRAME) { // FULL_FRAME
|
546 |
|
|
// read verification_type_info locals[number_of_locals];
|
547 |
|
|
locals = new ArrayList();
|
548 |
|
|
off = readTypes(locals,
|
549 |
|
|
isExtLocals,
|
550 |
|
|
isExtCodeSize,
|
551 |
|
|
cr,
|
552 |
|
|
off,
|
553 |
|
|
labels,
|
554 |
|
|
buf);
|
555 |
|
|
|
556 |
|
|
// read verification_type_info stack[number_of_stack_items];
|
557 |
|
|
stack = new ArrayList();
|
558 |
|
|
off = readTypes(stack,
|
559 |
|
|
isExtStack,
|
560 |
|
|
isExtCodeSize,
|
561 |
|
|
cr,
|
562 |
|
|
off,
|
563 |
|
|
labels,
|
564 |
|
|
buf);
|
565 |
|
|
|
566 |
|
|
} else {
|
567 |
|
|
throw new RuntimeException("Unknown frame type " + tag
|
568 |
|
|
+ " after offset " + offset);
|
569 |
|
|
|
570 |
|
|
}
|
571 |
|
|
}
|
572 |
|
|
|
573 |
|
|
offset += offsetDelta;
|
574 |
|
|
|
575 |
|
|
Label offsetLabel = getLabel(offset, labels);
|
576 |
|
|
|
577 |
|
|
frame = new StackMapFrame(offsetLabel, locals, stack);
|
578 |
|
|
frames.add(frame);
|
579 |
|
|
// System.err.println( tag +" " + offset +" delta:" + offsetDelta +
|
580 |
|
|
// " frameType:"+ frameType+" : "+ frame);
|
581 |
|
|
|
582 |
|
|
offset++;
|
583 |
|
|
}
|
584 |
|
|
|
585 |
|
|
return new StackMapTableAttribute(frames);
|
586 |
|
|
}
|
587 |
|
|
|
588 |
|
|
protected ByteVector write(
|
589 |
|
|
ClassWriter cw,
|
590 |
|
|
byte[] code,
|
591 |
|
|
int len,
|
592 |
|
|
int maxStack,
|
593 |
|
|
int maxLocals)
|
594 |
|
|
{
|
595 |
|
|
ByteVector bv = new ByteVector();
|
596 |
|
|
// TODO verify this value (MAX_SHORT)
|
597 |
|
|
boolean isExtCodeSize = code != null && code.length > MAX_SHORT;
|
598 |
|
|
writeSize(frames.size() - 1, bv, isExtCodeSize);
|
599 |
|
|
|
600 |
|
|
if (frames.size() < 2) {
|
601 |
|
|
return bv;
|
602 |
|
|
}
|
603 |
|
|
|
604 |
|
|
boolean isExtLocals = maxLocals > MAX_SHORT;
|
605 |
|
|
boolean isExtStack = maxStack > MAX_SHORT;
|
606 |
|
|
|
607 |
|
|
// skip the first frame
|
608 |
|
|
StackMapFrame frame = (StackMapFrame) frames.get(0);
|
609 |
|
|
List locals = frame.locals;
|
610 |
|
|
int offset = frame.label.getOffset();
|
611 |
|
|
|
612 |
|
|
for (int i = 1; i < frames.size(); i++) {
|
613 |
|
|
frame = (StackMapFrame) frames.get(i);
|
614 |
|
|
|
615 |
|
|
List clocals = frame.locals;
|
616 |
|
|
List cstack = frame.stack;
|
617 |
|
|
int coffset = frame.label.getOffset();
|
618 |
|
|
|
619 |
|
|
int clocalsSize = clocals.size();
|
620 |
|
|
int cstackSize = cstack.size();
|
621 |
|
|
|
622 |
|
|
int localsSize = locals.size();
|
623 |
|
|
|
624 |
|
|
int delta = coffset - offset;
|
625 |
|
|
|
626 |
|
|
int type = FULL_FRAME;
|
627 |
|
|
int k = 0;
|
628 |
|
|
if (cstackSize == 0) {
|
629 |
|
|
k = clocalsSize - localsSize;
|
630 |
|
|
switch (k) {
|
631 |
|
|
case -3:
|
632 |
|
|
case -2:
|
633 |
|
|
case -1:
|
634 |
|
|
type = CHOP_FRAME; // CHOP or FULL
|
635 |
|
|
localsSize = clocalsSize; // for full_frame check
|
636 |
|
|
break;
|
637 |
|
|
|
638 |
|
|
case 0:
|
639 |
|
|
// SAME, SAME_EXTENDED or FULL
|
640 |
|
|
type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
|
641 |
|
|
break;
|
642 |
|
|
|
643 |
|
|
case 1:
|
644 |
|
|
case 2:
|
645 |
|
|
case 3:
|
646 |
|
|
type = APPEND_FRAME; // APPEND or FULL
|
647 |
|
|
break;
|
648 |
|
|
}
|
649 |
|
|
} else if (localsSize == clocalsSize && cstackSize == 1) {
|
650 |
|
|
// SAME_LOCAL_1_STACK or FULL
|
651 |
|
|
type = delta < 63
|
652 |
|
|
? SAME_LOCALS_1_STACK_ITEM_FRAME
|
653 |
|
|
: SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
|
654 |
|
|
}
|
655 |
|
|
|
656 |
|
|
if (type != FULL_FRAME) {
|
657 |
|
|
// verify if stack and locals are the same
|
658 |
|
|
for (int j = 0; j < localsSize && type != FULL_FRAME; j++) {
|
659 |
|
|
if (!locals.get(j).equals(clocals.get(j)))
|
660 |
|
|
type = FULL_FRAME;
|
661 |
|
|
}
|
662 |
|
|
}
|
663 |
|
|
|
664 |
|
|
switch (type) {
|
665 |
|
|
case SAME_FRAME:
|
666 |
|
|
bv.putByte(delta);
|
667 |
|
|
break;
|
668 |
|
|
|
669 |
|
|
case SAME_LOCALS_1_STACK_ITEM_FRAME:
|
670 |
|
|
bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
|
671 |
|
|
writeTypeInfos(bv, cw, cstack, 0, 1);
|
672 |
|
|
break;
|
673 |
|
|
|
674 |
|
|
case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
|
675 |
|
|
bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED);
|
676 |
|
|
writeSize(delta, bv, isExtCodeSize);
|
677 |
|
|
writeTypeInfos(bv, cw, cstack, 0, 1);
|
678 |
|
|
break;
|
679 |
|
|
|
680 |
|
|
case SAME_FRAME_EXTENDED:
|
681 |
|
|
bv.putByte(SAME_FRAME_EXTENDED);
|
682 |
|
|
writeSize(delta, bv, isExtCodeSize);
|
683 |
|
|
break;
|
684 |
|
|
|
685 |
|
|
case CHOP_FRAME:
|
686 |
|
|
bv.putByte(SAME_FRAME_EXTENDED + k); // negative k
|
687 |
|
|
writeSize(delta, bv, isExtCodeSize);
|
688 |
|
|
break;
|
689 |
|
|
|
690 |
|
|
case APPEND_FRAME:
|
691 |
|
|
bv.putByte(SAME_FRAME_EXTENDED + k); // positive k
|
692 |
|
|
writeSize(delta, bv, isExtCodeSize);
|
693 |
|
|
writeTypeInfos(bv,
|
694 |
|
|
cw,
|
695 |
|
|
clocals,
|
696 |
|
|
clocalsSize - 1,
|
697 |
|
|
clocalsSize);
|
698 |
|
|
break;
|
699 |
|
|
|
700 |
|
|
case FULL_FRAME:
|
701 |
|
|
bv.putByte(FULL_FRAME);
|
702 |
|
|
writeSize(delta, bv, isExtCodeSize);
|
703 |
|
|
writeSize(clocalsSize, bv, isExtLocals);
|
704 |
|
|
writeTypeInfos(bv, cw, clocals, 0, clocalsSize);
|
705 |
|
|
writeSize(cstackSize, bv, isExtStack);
|
706 |
|
|
writeTypeInfos(bv, cw, cstack, 0, cstackSize);
|
707 |
|
|
break;
|
708 |
|
|
|
709 |
|
|
default:
|
710 |
|
|
throw new RuntimeException();
|
711 |
|
|
}
|
712 |
|
|
offset = coffset + 1; // compensating non first offset
|
713 |
|
|
locals = clocals;
|
714 |
|
|
}
|
715 |
|
|
return bv;
|
716 |
|
|
}
|
717 |
|
|
|
718 |
|
|
private void writeSize(int delta, ByteVector bv, boolean isExt) {
|
719 |
|
|
if (isExt) {
|
720 |
|
|
bv.putInt(delta);
|
721 |
|
|
} else {
|
722 |
|
|
bv.putShort(delta);
|
723 |
|
|
}
|
724 |
|
|
}
|
725 |
|
|
|
726 |
|
|
private void writeTypeInfos(
|
727 |
|
|
ByteVector bv,
|
728 |
|
|
ClassWriter cw,
|
729 |
|
|
List info,
|
730 |
|
|
int start,
|
731 |
|
|
int end)
|
732 |
|
|
{
|
733 |
|
|
for (int j = start; j < end; j++) {
|
734 |
|
|
StackMapType typeInfo = (StackMapType) info.get(j);
|
735 |
|
|
bv.putByte(typeInfo.getType());
|
736 |
|
|
|
737 |
|
|
switch (typeInfo.getType()) {
|
738 |
|
|
case StackMapType.ITEM_Object: //
|
739 |
|
|
bv.putShort(cw.newClass(typeInfo.getObject()));
|
740 |
|
|
break;
|
741 |
|
|
|
742 |
|
|
case StackMapType.ITEM_Uninitialized: //
|
743 |
|
|
bv.putShort(typeInfo.getLabel().getOffset());
|
744 |
|
|
break;
|
745 |
|
|
|
746 |
|
|
}
|
747 |
|
|
}
|
748 |
|
|
}
|
749 |
|
|
|
750 |
|
|
public static int getMethodOff(ClassReader cr, int codeOff, char[] buf) {
|
751 |
|
|
int off = cr.header + 6;
|
752 |
|
|
|
753 |
|
|
int interfacesCount = cr.readUnsignedShort(off);
|
754 |
|
|
off += 2 + interfacesCount * 2;
|
755 |
|
|
|
756 |
|
|
int fieldsCount = cr.readUnsignedShort(off);
|
757 |
|
|
off += 2;
|
758 |
|
|
for (; fieldsCount > 0; --fieldsCount) {
|
759 |
|
|
int attrCount = cr.readUnsignedShort(off + 6); // field attributes
|
760 |
|
|
off += 8;
|
761 |
|
|
for (; attrCount > 0; --attrCount) {
|
762 |
|
|
off += 6 + cr.readInt(off + 2);
|
763 |
|
|
}
|
764 |
|
|
}
|
765 |
|
|
|
766 |
|
|
int methodsCount = cr.readUnsignedShort(off);
|
767 |
|
|
off += 2;
|
768 |
|
|
for (; methodsCount > 0; --methodsCount) {
|
769 |
|
|
int methodOff = off;
|
770 |
|
|
int attrCount = cr.readUnsignedShort(off + 6); // method attributes
|
771 |
|
|
off += 8;
|
772 |
|
|
for (; attrCount > 0; --attrCount) {
|
773 |
|
|
String attrName = cr.readUTF8(off, buf);
|
774 |
|
|
off += 6;
|
775 |
|
|
if (attrName.equals("Code")) {
|
776 |
|
|
if (codeOff == off) {
|
777 |
|
|
return methodOff;
|
778 |
|
|
}
|
779 |
|
|
}
|
780 |
|
|
off += cr.readInt(off - 4);
|
781 |
|
|
}
|
782 |
|
|
}
|
783 |
|
|
|
784 |
|
|
return -1;
|
785 |
|
|
}
|
786 |
|
|
|
787 |
|
|
/**
|
788 |
|
|
* Use method signature and access flags to resolve initial locals state.
|
789 |
|
|
*
|
790 |
|
|
* @param className name of the method's owner class.
|
791 |
|
|
* @param access access flags of the method.
|
792 |
|
|
* @param methodName name of the method.
|
793 |
|
|
* @param methodDesc descriptor of the method.
|
794 |
|
|
* @return list of <code>StackMapType</code> instances representing locals
|
795 |
|
|
* for an initial frame.
|
796 |
|
|
*/
|
797 |
|
|
public static List calculateLocals(
|
798 |
|
|
String className,
|
799 |
|
|
int access,
|
800 |
|
|
String methodName,
|
801 |
|
|
String methodDesc)
|
802 |
|
|
{
|
803 |
|
|
List locals = new ArrayList();
|
804 |
|
|
|
805 |
|
|
// TODO
|
806 |
|
|
if ("<init>".equals(methodName)
|
807 |
|
|
&& !className.equals("java/lang/Object"))
|
808 |
|
|
{
|
809 |
|
|
StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_UninitializedThis);
|
810 |
|
|
typeInfo.setObject(className); // this
|
811 |
|
|
locals.add(typeInfo);
|
812 |
|
|
} else if ((access & Opcodes.ACC_STATIC) == 0) {
|
813 |
|
|
StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_Object);
|
814 |
|
|
typeInfo.setObject(className); // this
|
815 |
|
|
locals.add(typeInfo);
|
816 |
|
|
}
|
817 |
|
|
|
818 |
|
|
Type[] types = Type.getArgumentTypes(methodDesc);
|
819 |
|
|
for (int i = 0; i < types.length; i++) {
|
820 |
|
|
Type t = types[i];
|
821 |
|
|
StackMapType smt;
|
822 |
|
|
switch (t.getSort()) {
|
823 |
|
|
case Type.LONG:
|
824 |
|
|
smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long);
|
825 |
|
|
break;
|
826 |
|
|
case Type.DOUBLE:
|
827 |
|
|
smt = StackMapType.getTypeInfo(StackMapType.ITEM_Double);
|
828 |
|
|
break;
|
829 |
|
|
|
830 |
|
|
case Type.FLOAT:
|
831 |
|
|
smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float);
|
832 |
|
|
break;
|
833 |
|
|
|
834 |
|
|
case Type.ARRAY:
|
835 |
|
|
case Type.OBJECT:
|
836 |
|
|
smt = StackMapType.getTypeInfo(StackMapType.ITEM_Object);
|
837 |
|
|
smt.setObject(t.getDescriptor()); // TODO verify name
|
838 |
|
|
break;
|
839 |
|
|
|
840 |
|
|
default:
|
841 |
|
|
smt = StackMapType.getTypeInfo(StackMapType.ITEM_Integer);
|
842 |
|
|
break;
|
843 |
|
|
}
|
844 |
|
|
}
|
845 |
|
|
|
846 |
|
|
return locals;
|
847 |
|
|
}
|
848 |
|
|
|
849 |
|
|
private int readTypes(
|
850 |
|
|
List info,
|
851 |
|
|
boolean isExt,
|
852 |
|
|
boolean isExtCodeSize,
|
853 |
|
|
ClassReader cr,
|
854 |
|
|
int off,
|
855 |
|
|
Label[] labels,
|
856 |
|
|
char[] buf)
|
857 |
|
|
{
|
858 |
|
|
int n = 0;
|
859 |
|
|
if (isExt) {
|
860 |
|
|
n = cr.readInt(off);
|
861 |
|
|
off += 4;
|
862 |
|
|
} else {
|
863 |
|
|
n = cr.readUnsignedShort(off);
|
864 |
|
|
off += 2;
|
865 |
|
|
}
|
866 |
|
|
|
867 |
|
|
for (; n > 0; n--) {
|
868 |
|
|
off = readType(info, isExtCodeSize, cr, off, labels, buf);
|
869 |
|
|
}
|
870 |
|
|
return off;
|
871 |
|
|
}
|
872 |
|
|
|
873 |
|
|
private int readType(
|
874 |
|
|
List info,
|
875 |
|
|
boolean isExtCodeSize,
|
876 |
|
|
ClassReader cr,
|
877 |
|
|
int off,
|
878 |
|
|
Label[] labels,
|
879 |
|
|
char[] buf)
|
880 |
|
|
{
|
881 |
|
|
int itemType = cr.readByte(off++);
|
882 |
|
|
StackMapType typeInfo = StackMapType.getTypeInfo(itemType);
|
883 |
|
|
info.add(typeInfo);
|
884 |
|
|
switch (itemType) {
|
885 |
|
|
// case StackMapType.ITEM_Long: //
|
886 |
|
|
// case StackMapType.ITEM_Double: //
|
887 |
|
|
// info.add(StackMapType.getTypeInfo(StackMapType.ITEM_Top));
|
888 |
|
|
// break;
|
889 |
|
|
|
890 |
|
|
case StackMapType.ITEM_Object: //
|
891 |
|
|
typeInfo.setObject(cr.readClass(off, buf));
|
892 |
|
|
off += 2;
|
893 |
|
|
break;
|
894 |
|
|
|
895 |
|
|
case StackMapType.ITEM_Uninitialized: //
|
896 |
|
|
int offset;
|
897 |
|
|
if (isExtCodeSize) {
|
898 |
|
|
offset = cr.readInt(off);
|
899 |
|
|
off += 4;
|
900 |
|
|
} else {
|
901 |
|
|
offset = cr.readUnsignedShort(off);
|
902 |
|
|
off += 2;
|
903 |
|
|
}
|
904 |
|
|
|
905 |
|
|
typeInfo.setLabel(getLabel(offset, labels));
|
906 |
|
|
break;
|
907 |
|
|
}
|
908 |
|
|
return off;
|
909 |
|
|
}
|
910 |
|
|
|
911 |
|
|
private Label getLabel(int offset, Label[] labels) {
|
912 |
|
|
Label l = labels[offset];
|
913 |
|
|
if (l != null) {
|
914 |
|
|
return l;
|
915 |
|
|
}
|
916 |
|
|
return labels[offset] = new Label();
|
917 |
|
|
}
|
918 |
|
|
|
919 |
|
|
public String toString() {
|
920 |
|
|
StringBuffer sb = new StringBuffer("StackMapTable[");
|
921 |
|
|
for (int i = 0; i < frames.size(); i++) {
|
922 |
|
|
sb.append('\n').append('[').append(frames.get(i)).append(']');
|
923 |
|
|
}
|
924 |
|
|
sb.append("\n]");
|
925 |
|
|
return sb.toString();
|
926 |
|
|
}
|
927 |
|
|
}
|