2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
30 package org.objectweb.asm.attrs;
32 import java.util.ArrayList;
33 import java.util.HashSet;
34 import java.util.Iterator;
35 import java.util.List;
38 import org.objectweb.asm.Attribute;
39 import org.objectweb.asm.ByteVector;
40 import org.objectweb.asm.ClassReader;
41 import org.objectweb.asm.ClassWriter;
42 import org.objectweb.asm.Label;
45 * StackMapAttribute is used by CDLC preverifier. Definition is given in
46 * appendix "CLDC Byte Code Typechecker Specification" from CDLC 1.1
47 * specification. <p> <i>Note that this implementation does not calculate
48 * StackMapFrame structures from the method bytecode. If method code is changed
49 * or generated from scratch, then developer is responsible to prepare a correct
50 * StackMapFrame structures.</i> <p> The format of the stack map in the class
51 * file is given below. In the following, <ul> <li>if the length of the
52 * method's byte code1 is 65535 or less, then <tt>uoffset</tt> represents the
53 * type u2; otherwise <tt>uoffset</tt> represents the type u4.</li> <li>If
54 * the maximum number of local variables for the method is 65535 or less, then
55 * <tt>ulocalvar</tt> represents the type u2; otherwise <tt>ulocalvar</tt>
56 * represents the type u4.</li> <li>If the maximum size of the operand stack
57 * is 65535 or less, then <tt>ustack</tt> represents the type u2; otherwise
58 * ustack represents the type u4.</li> </ul>
61 * stack_map { // attribute StackMap
62 * u2 attribute_name_index;
64 * uoffset number_of_entries;
65 * stack_map_frame entries[number_of_entries];
69 * Each stack map frame has the following format:
74 * ulocalvar number_of_locals;
75 * verification_type_info locals[number_of_locals];
76 * ustack number_of_stack_items;
77 * verification_type_info stack[number_of_stack_items];
81 * The <tt>verification_type_info</tt> structure consists of a one-byte tag
82 * followed by zero or more bytes, giving more information about the tag. Each
83 * <tt>verification_type_info</tt> structure specifies the verification type
84 * of one or two locations.
87 * union verification_type_info {
89 * Integer_variable_info;
90 * Float_variable_info;
92 * Double_variable_info;
94 * UninitializedThis_variable_info;
95 * Object_variable_info;
96 * Uninitialized_variable_info;
100 * u1 tag = ITEM_Top; // 0
103 * Integer_variable_info {
104 * u1 tag = ITEM_Integer; // 1
107 * Float_variable_info {
108 * u1 tag = ITEM_Float; // 2
111 * Long_variable_info {
112 * u1 tag = ITEM_Long; // 4
115 * Double_variable_info {
116 * u1 tag = ITEM_Double; // 3
119 * Null_variable_info {
120 * u1 tag = ITEM_Null; // 5
123 * UninitializedThis_variable_info {
124 * u1 tag = ITEM_UninitializedThis; // 6
127 * Object_variable_info {
128 * u1 tag = ITEM_Object; // 7
132 * Uninitialized_variable_info {
133 * u1 tag = ITEM_Uninitialized // 8
138 * @see <a href="http://www.jcp.org/en/jsr/detail?id=139">JSR 139 : Connected
139 * Limited Device Configuration 1.1</a>
141 * @author Eugene Kuleshov
143 public class StackMapAttribute extends Attribute {
145 static final int MAX_SIZE = 65535;
148 * A List of <code>StackMapFrame</code> instances.
150 public List frames = new ArrayList();
152 public StackMapAttribute() {
156 public StackMapAttribute(List frames) {
158 this.frames = frames;
161 public List getFrames() {
165 public StackMapFrame getFrame(Label label) {
166 for (int i = 0; i < frames.size(); i++) {
167 StackMapFrame frame = (StackMapFrame) frames.get(i);
168 if (frame.label == label) {
175 public boolean isUnknown() {
179 public boolean isCodeAttribute() {
183 protected Attribute read(
191 StackMapAttribute attr = new StackMapAttribute();
192 // note that this is not the size of Code attribute
193 boolean isExtCodeSize = cr.readInt(codeOff + 4) > MAX_SIZE;
194 boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > MAX_SIZE;
195 boolean isExtStack = cr.readUnsignedShort(codeOff) > MAX_SIZE;
199 size = cr.readInt(off);
202 size = cr.readUnsignedShort(off);
205 for (int i = 0; i < size; i++) {
208 offset = cr.readInt(off);
211 offset = cr.readUnsignedShort(off);
215 Label label = getLabel(offset, labels);
216 List locals = new ArrayList();
217 List stack = new ArrayList();
219 off = readTypeInfo(cr,
226 off = readTypeInfo(cr,
234 attr.frames.add(new StackMapFrame(label, locals, stack));
239 private int readTypeInfo(
253 n = cr.readUnsignedShort(off);
256 for (int j = 0; j < n; j++) {
257 int itemType = cr.readByte(off++);
258 StackMapType typeInfo = StackMapType.getTypeInfo(itemType);
261 case StackMapType.ITEM_Object: //
262 typeInfo.setObject(cr.readClass(off, buf));
265 case StackMapType.ITEM_Uninitialized: //
268 offset = cr.readInt(off);
271 offset = cr.readUnsignedShort(off);
274 typeInfo.setLabel(getLabel(offset, labels));
281 private void writeTypeInfo(ByteVector bv, ClassWriter cw, List info, int max)
283 if (max > StackMapAttribute.MAX_SIZE) {
284 bv.putInt(info.size());
286 bv.putShort(info.size());
288 for (int j = 0; j < info.size(); j++) {
289 StackMapType typeInfo = (StackMapType) info.get(j);
290 bv.putByte(typeInfo.getType());
291 switch (typeInfo.getType()) {
292 case StackMapType.ITEM_Object: //
293 bv.putShort(cw.newClass(typeInfo.getObject()));
296 case StackMapType.ITEM_Uninitialized: //
297 bv.putShort(typeInfo.getLabel().getOffset());
304 private Label getLabel(int offset, Label[] labels) {
305 Label l = labels[offset];
309 return labels[offset] = new Label();
312 protected ByteVector write(
319 ByteVector bv = new ByteVector();
320 if (code != null && code.length > MAX_SIZE) { // TODO verify value
321 bv.putInt(frames.size());
323 bv.putShort(frames.size());
325 for (int i = 0; i < frames.size(); i++) {
326 writeFrame((StackMapFrame) frames.get(i),
335 protected Label[] getLabels() {
336 HashSet labels = new HashSet();
337 for (int i = 0; i < frames.size(); i++) {
338 getFrameLabels((StackMapFrame) frames.get(i), labels);
340 return (Label[]) labels.toArray(new Label[labels.size()]);
343 private void writeFrame(
350 bv.putShort(frame.label.getOffset());
351 writeTypeInfo(bv, cw, frame.locals, maxLocals);
352 writeTypeInfo(bv, cw, frame.stack, maxStack);
355 private void getFrameLabels(StackMapFrame frame, Set labels) {
356 labels.add(frame.label);
357 getTypeInfoLabels(labels, frame.locals);
358 getTypeInfoLabels(labels, frame.stack);
361 private void getTypeInfoLabels(Set labels, List info) {
362 for (Iterator it = info.iterator(); it.hasNext();) {
363 StackMapType typeInfo = (StackMapType) it.next();
364 if (typeInfo.getType() == StackMapType.ITEM_Uninitialized) {
365 labels.add(typeInfo.getLabel());
370 public String toString() {
371 StringBuffer sb = new StringBuffer("StackMap[");
372 for (int i = 0; i < frames.size(); i++) {
373 sb.append('\n').append('[').append(frames.get(i)).append(']');
376 return sb.toString();