001    /*
002     * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.classfile;
027    
028    import java.io.IOException;
029    
030    /**
031     * See JVMS3, section 4.8.4.
032     *
033     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
034     *  you write code that depends on this, you do so at your own risk.
035     *  This code and its internal interfaces are subject to change or
036     *  deletion without notice.</b>
037     */
038    public class StackMapTable_attribute extends Attribute {
039        static class InvalidStackMap extends AttributeException {
040            private static final long serialVersionUID = -5659038410855089780L;
041            InvalidStackMap(String msg) {
042                super(msg);
043            }
044        }
045    
046        StackMapTable_attribute(ClassReader cr, int name_index, int length)
047                throws IOException, InvalidStackMap {
048            super(name_index, length);
049            number_of_entries = cr.readUnsignedShort();
050            entries = new stack_map_frame[number_of_entries];
051            for (int i = 0; i < number_of_entries; i++)
052                entries[i] = stack_map_frame.read(cr);
053        }
054    
055        public StackMapTable_attribute(ConstantPool constant_pool, stack_map_frame[] entries)
056                throws ConstantPoolException {
057            this(constant_pool.getUTF8Index(Attribute.StackMapTable), entries);
058        }
059    
060        public StackMapTable_attribute(int name_index, stack_map_frame[] entries) {
061            super(name_index, length(entries));
062            this.number_of_entries = entries.length;
063            this.entries = entries;
064        }
065    
066        public <R, D> R accept(Visitor<R, D> visitor, D data) {
067            return visitor.visitStackMapTable(this, data);
068        }
069    
070        static int length(stack_map_frame[] entries) {
071            int n = 2;
072            for (stack_map_frame entry: entries)
073                n += entry.length();
074            return n;
075        }
076    
077        public final int number_of_entries;
078        public final stack_map_frame entries[];
079    
080        public static abstract class stack_map_frame {
081            static stack_map_frame read(ClassReader cr)
082                    throws IOException, InvalidStackMap {
083                int frame_type = cr.readUnsignedByte();
084                if (frame_type <= 63)
085                    return new same_frame(frame_type);
086                else if (frame_type <= 127)
087                    return new same_locals_1_stack_item_frame(frame_type, cr);
088                else if (frame_type <= 246)
089                    throw new Error("unknown frame_type " + frame_type);
090                else if (frame_type == 247)
091                    return new same_locals_1_stack_item_frame_extended(frame_type, cr);
092                else if (frame_type <= 250)
093                    return new chop_frame(frame_type, cr);
094                else if (frame_type == 251)
095                    return new same_frame_extended(frame_type, cr);
096                else if (frame_type <= 254)
097                    return new append_frame(frame_type, cr);
098                else
099                    return new full_frame(frame_type, cr);
100            }
101    
102            protected stack_map_frame(int frame_type) {
103                this.frame_type = frame_type;
104            }
105    
106            public int length() {
107                return 1;
108            }
109    
110            public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
111    
112            public final int frame_type;
113    
114            public static interface Visitor<R,P> {
115                R visit_same_frame(same_frame frame, P p);
116                R visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, P p);
117                R visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, P p);
118                R visit_chop_frame(chop_frame frame, P p);
119                R visit_same_frame_extended(same_frame_extended frame, P p);
120                R visit_append_frame(append_frame frame, P p);
121                R visit_full_frame(full_frame frame, P p);
122            }
123        }
124    
125        public static class same_frame extends stack_map_frame {
126            same_frame(int frame_type) {
127                super(frame_type);
128            }
129    
130            public <R, D> R accept(Visitor<R, D> visitor, D data) {
131                return visitor.visit_same_frame(this, data);
132            }
133        }
134    
135        public static class same_locals_1_stack_item_frame extends stack_map_frame {
136            same_locals_1_stack_item_frame(int frame_type, ClassReader cr)
137                    throws IOException, InvalidStackMap {
138                super(frame_type);
139                stack = new verification_type_info[1];
140                stack[0] = verification_type_info.read(cr);
141            }
142    
143            @Override
144            public int length() {
145                return super.length() + stack[0].length();
146            }
147    
148            public <R, D> R accept(Visitor<R, D> visitor, D data) {
149                return visitor.visit_same_locals_1_stack_item_frame(this, data);
150            }
151    
152            public final verification_type_info[] stack;
153        }
154    
155        public static class same_locals_1_stack_item_frame_extended extends stack_map_frame {
156            same_locals_1_stack_item_frame_extended(int frame_type, ClassReader cr)
157                    throws IOException, InvalidStackMap {
158                super(frame_type);
159                offset_delta = cr.readUnsignedShort();
160                stack = new verification_type_info[1];
161                stack[0] = verification_type_info.read(cr);
162            }
163    
164            @Override
165            public int length() {
166                return super.length() + 2 + stack[0].length();
167            }
168    
169            public <R, D> R accept(Visitor<R, D> visitor, D data) {
170                return visitor.visit_same_locals_1_stack_item_frame_extended(this, data);
171            }
172    
173            public final int offset_delta;
174            public final verification_type_info[] stack;
175        }
176    
177        public static class chop_frame extends stack_map_frame {
178            chop_frame(int frame_type, ClassReader cr) throws IOException {
179                super(frame_type);
180                offset_delta = cr.readUnsignedShort();
181            }
182    
183            @Override
184            public int length() {
185                return super.length() + 2;
186            }
187    
188            public <R, D> R accept(Visitor<R, D> visitor, D data) {
189                return visitor.visit_chop_frame(this, data);
190            }
191    
192            public final int offset_delta;
193        }
194    
195        public static class same_frame_extended extends stack_map_frame {
196            same_frame_extended(int frame_type, ClassReader cr) throws IOException {
197                super(frame_type);
198                offset_delta = cr.readUnsignedShort();
199            }
200    
201            @Override
202            public int length() {
203                return super.length() + 2;
204            }
205    
206            public <R, D> R accept(Visitor<R, D> visitor, D data) {
207                return visitor.visit_same_frame_extended(this, data);
208            }
209    
210            public final int offset_delta;
211        }
212    
213        public static class append_frame extends stack_map_frame {
214            append_frame(int frame_type, ClassReader cr)
215                    throws IOException, InvalidStackMap {
216                super(frame_type);
217                offset_delta = cr.readUnsignedShort();
218                locals = new verification_type_info[frame_type - 251];
219                for (int i = 0; i < locals.length; i++)
220                    locals[i] = verification_type_info.read(cr);
221            }
222    
223            @Override
224            public int length() {
225                int n = super.length() + 2;
226                for (verification_type_info local: locals)
227                    n += local.length();
228                return n;
229            }
230    
231            public <R, D> R accept(Visitor<R, D> visitor, D data) {
232                return visitor.visit_append_frame(this, data);
233            }
234    
235            public final int offset_delta;
236            public final verification_type_info[] locals;
237        }
238    
239        public static class full_frame extends stack_map_frame {
240            full_frame(int frame_type, ClassReader cr)
241                    throws IOException, InvalidStackMap {
242                super(frame_type);
243                offset_delta = cr.readUnsignedShort();
244                number_of_locals = cr.readUnsignedShort();
245                locals = new verification_type_info[number_of_locals];
246                for (int i = 0; i < locals.length; i++)
247                    locals[i] = verification_type_info.read(cr);
248                number_of_stack_items = cr.readUnsignedShort();
249                stack = new verification_type_info[number_of_stack_items];
250                for (int i = 0; i < stack.length; i++)
251                    stack[i] = verification_type_info.read(cr);
252            }
253    
254            @Override
255            public int length() {
256                int n = super.length() + 2;
257                for (verification_type_info local: locals)
258                    n += local.length();
259                n += 2;
260                for (verification_type_info item: stack)
261                    n += item.length();
262                return n;
263            }
264    
265            public <R, D> R accept(Visitor<R, D> visitor, D data) {
266                return visitor.visit_full_frame(this, data);
267            }
268    
269            public final int offset_delta;
270            public final int number_of_locals;
271            public final verification_type_info[] locals;
272            public final int number_of_stack_items;
273            public final verification_type_info[] stack;
274        }
275    
276        public static class verification_type_info {
277            public static final int ITEM_Top = 0;
278            public static final int ITEM_Integer = 1;
279            public static final int ITEM_Float = 2;
280            public static final int ITEM_Long = 4;
281            public static final int ITEM_Double = 3;
282            public static final int ITEM_Null = 5;
283            public static final int ITEM_UninitializedThis = 6;
284            public static final int ITEM_Object = 7;
285            public static final int ITEM_Uninitialized = 8;
286    
287            static verification_type_info read(ClassReader cr)
288                    throws IOException, InvalidStackMap {
289                int tag = cr.readUnsignedByte();
290                switch (tag) {
291                case ITEM_Top:
292                case ITEM_Integer:
293                case ITEM_Float:
294                case ITEM_Long:
295                case ITEM_Double:
296                case ITEM_Null:
297                case ITEM_UninitializedThis:
298                    return new verification_type_info(tag);
299    
300                case ITEM_Object:
301                    return new Object_variable_info(cr);
302    
303                case ITEM_Uninitialized:
304                    return new Uninitialized_variable_info(cr);
305    
306                default:
307                    throw new InvalidStackMap("unrecognized verification_type_info tag");
308                }
309            }
310    
311            verification_type_info(int tag) {
312                this.tag = tag;
313            }
314    
315            public int length() {
316                return 1;
317            }
318    
319            public final int tag;
320        }
321    
322        public static class Object_variable_info extends verification_type_info {
323            Object_variable_info(ClassReader cr) throws IOException {
324                super(ITEM_Object);
325                cpool_index = cr.readUnsignedShort();
326            }
327    
328            @Override
329            public int length() {
330                return super.length() + 2;
331            }
332    
333            public final int cpool_index;
334        }
335    
336        public static class Uninitialized_variable_info extends verification_type_info {
337            Uninitialized_variable_info(ClassReader cr) throws IOException {
338                super(ITEM_Uninitialized);
339                offset = cr.readUnsignedShort();
340            }
341    
342            @Override
343            public int length() {
344                return super.length() + 2;
345            }
346    
347            public final int offset;
348    
349        }
350    }