1 /*
  2  * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package com.sun.tools.classfile;
 27 
 28 import java.io.IOException;
 29 
 30 /**
 31  * See JVMS, section 4.8.4.
 32  *
 33  *  <p><b>This is NOT part of any supported API.
 34  *  If you write code that depends on this, you do so at your own risk.
 35  *  This code and its internal interfaces are subject to change or
 36  *  deletion without notice.</b>
 37  */
 38 public class StackMapTable_attribute extends Attribute {
 39     static class InvalidStackMap extends AttributeException {
 40         private static final long serialVersionUID = -5659038410855089780L;
 41         InvalidStackMap(String msg) {
 42             super(msg);
 43         }
 44     }
 45 
 46     StackMapTable_attribute(ClassReader cr, int name_index, int length)
 47             throws IOException, InvalidStackMap {
 48         super(name_index, length);
 49         number_of_entries = cr.readUnsignedShort();
 50         entries = new stack_map_frame[number_of_entries];
 51         for (int i = 0; i < number_of_entries; i++)
 52             entries[i] = stack_map_frame.read(cr);
 53     }
 54 
 55     public StackMapTable_attribute(ConstantPool constant_pool, stack_map_frame[] entries)
 56             throws ConstantPoolException {
 57         this(constant_pool.getUTF8Index(Attribute.StackMapTable), entries);
 58     }
 59 
 60     public StackMapTable_attribute(int name_index, stack_map_frame[] entries) {
 61         super(name_index, length(entries));
 62         this.number_of_entries = entries.length;
 63         this.entries = entries;
 64     }
 65 
 66     public <R, D> R accept(Visitor<R, D> visitor, D data) {
 67         return visitor.visitStackMapTable(this, data);
 68     }
 69 
 70     static int length(stack_map_frame[] entries) {
 71         int n = 2;
 72         for (stack_map_frame entry: entries)
 73             n += entry.length();
 74         return n;
 75     }
 76 
 77     public final int number_of_entries;
 78     public final stack_map_frame entries[];
 79 
 80     public abstract static class stack_map_frame {
 81         static stack_map_frame read(ClassReader cr)
 82                 throws IOException, InvalidStackMap {
 83             int frame_type = cr.readUnsignedByte();
 84             if (frame_type <= 63)
 85                 return new same_frame(frame_type);
 86             else if (frame_type <= 127)
 87                 return new same_locals_1_stack_item_frame(frame_type, cr);
 88             else if (frame_type <= 246)
 89                 throw new Error("unknown frame_type " + frame_type);
 90             else if (frame_type == 247)
 91                 return new same_locals_1_stack_item_frame_extended(frame_type, cr);
 92             else if (frame_type <= 250)
 93                 return new chop_frame(frame_type, cr);
 94             else if (frame_type == 251)
 95                 return new same_frame_extended(frame_type, cr);
 96             else if (frame_type <= 254)
 97                 return new append_frame(frame_type, cr);
 98             else
 99                 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 int getOffsetDelta();
111 
112         public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
113 
114         public final int frame_type;
115 
116         public static interface Visitor<R,P> {
117             R visit_same_frame(same_frame frame, P p);
118             R visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, P p);
119             R visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, P p);
120             R visit_chop_frame(chop_frame frame, P p);
121             R visit_same_frame_extended(same_frame_extended frame, P p);
122             R visit_append_frame(append_frame frame, P p);
123             R visit_full_frame(full_frame frame, P p);
124         }
125     }
126 
127     public static class same_frame extends stack_map_frame {
128         same_frame(int frame_type) {
129             super(frame_type);
130         }
131 
132         public <R, D> R accept(Visitor<R, D> visitor, D data) {
133             return visitor.visit_same_frame(this, data);
134         }
135 
136         public int getOffsetDelta() {
137             return frame_type;
138         }
139     }
140 
141     public static class same_locals_1_stack_item_frame extends stack_map_frame {
142         same_locals_1_stack_item_frame(int frame_type, ClassReader cr)
143                 throws IOException, InvalidStackMap {
144             super(frame_type);
145             stack = new verification_type_info[1];
146             stack[0] = verification_type_info.read(cr);
147         }
148 
149         @Override
150         public int length() {
151             return super.length() + stack[0].length();
152         }
153 
154         public <R, D> R accept(Visitor<R, D> visitor, D data) {
155             return visitor.visit_same_locals_1_stack_item_frame(this, data);
156         }
157 
158         public int getOffsetDelta() {
159             return frame_type - 64;
160         }
161 
162         public final verification_type_info[] stack;
163     }
164 
165     public static class same_locals_1_stack_item_frame_extended extends stack_map_frame {
166         same_locals_1_stack_item_frame_extended(int frame_type, ClassReader cr)
167                 throws IOException, InvalidStackMap {
168             super(frame_type);
169             offset_delta = cr.readUnsignedShort();
170             stack = new verification_type_info[1];
171             stack[0] = verification_type_info.read(cr);
172         }
173 
174         @Override
175         public int length() {
176             return super.length() + 2 + stack[0].length();
177         }
178 
179         public <R, D> R accept(Visitor<R, D> visitor, D data) {
180             return visitor.visit_same_locals_1_stack_item_frame_extended(this, data);
181         }
182 
183         public int getOffsetDelta() {
184             return offset_delta;
185         }
186 
187         public final int offset_delta;
188         public final verification_type_info[] stack;
189     }
190 
191     public static class chop_frame extends stack_map_frame {
192         chop_frame(int frame_type, ClassReader cr) throws IOException {
193             super(frame_type);
194             offset_delta = cr.readUnsignedShort();
195         }
196 
197         @Override
198         public int length() {
199             return super.length() + 2;
200         }
201 
202         public <R, D> R accept(Visitor<R, D> visitor, D data) {
203             return visitor.visit_chop_frame(this, data);
204         }
205 
206         public int getOffsetDelta() {
207             return offset_delta;
208         }
209 
210         public final int offset_delta;
211     }
212 
213     public static class same_frame_extended extends stack_map_frame {
214         same_frame_extended(int frame_type, ClassReader cr) throws IOException {
215             super(frame_type);
216             offset_delta = cr.readUnsignedShort();
217         }
218 
219         @Override
220         public int length() {
221             return super.length() + 2;
222         }
223 
224         public <R, D> R accept(Visitor<R, D> visitor, D data) {
225             return visitor.visit_same_frame_extended(this, data);
226         }
227 
228         public int getOffsetDelta() {
229             return offset_delta;
230         }
231 
232         public final int offset_delta;
233     }
234 
235     public static class append_frame extends stack_map_frame {
236         append_frame(int frame_type, ClassReader cr)
237                 throws IOException, InvalidStackMap {
238             super(frame_type);
239             offset_delta = cr.readUnsignedShort();
240             locals = new verification_type_info[frame_type - 251];
241             for (int i = 0; i < locals.length; i++)
242                 locals[i] = verification_type_info.read(cr);
243         }
244 
245         @Override
246         public int length() {
247             int n = super.length() + 2;
248             for (verification_type_info local: locals)
249                 n += local.length();
250             return n;
251         }
252 
253         public <R, D> R accept(Visitor<R, D> visitor, D data) {
254             return visitor.visit_append_frame(this, data);
255         }
256 
257         public int getOffsetDelta() {
258             return offset_delta;
259         }
260 
261         public final int offset_delta;
262         public final verification_type_info[] locals;
263     }
264 
265     public static class full_frame extends stack_map_frame {
266         full_frame(int frame_type, ClassReader cr)
267                 throws IOException, InvalidStackMap {
268             super(frame_type);
269             offset_delta = cr.readUnsignedShort();
270             number_of_locals = cr.readUnsignedShort();
271             locals = new verification_type_info[number_of_locals];
272             for (int i = 0; i < locals.length; i++)
273                 locals[i] = verification_type_info.read(cr);
274             number_of_stack_items = cr.readUnsignedShort();
275             stack = new verification_type_info[number_of_stack_items];
276             for (int i = 0; i < stack.length; i++)
277                 stack[i] = verification_type_info.read(cr);
278         }
279 
280         @Override
281         public int length() {
282             int n = super.length() + 2;
283             for (verification_type_info local: locals)
284                 n += local.length();
285             n += 2;
286             for (verification_type_info item: stack)
287                 n += item.length();
288             return n;
289         }
290 
291         public <R, D> R accept(Visitor<R, D> visitor, D data) {
292             return visitor.visit_full_frame(this, data);
293         }
294 
295         public int getOffsetDelta() {
296             return offset_delta;
297         }
298 
299         public final int offset_delta;
300         public final int number_of_locals;
301         public final verification_type_info[] locals;
302         public final int number_of_stack_items;
303         public final verification_type_info[] stack;
304     }
305 
306     public static class verification_type_info {
307         public static final int ITEM_Top = 0;
308         public static final int ITEM_Integer = 1;
309         public static final int ITEM_Float = 2;
310         public static final int ITEM_Long = 4;
311         public static final int ITEM_Double = 3;
312         public static final int ITEM_Null = 5;
313         public static final int ITEM_UninitializedThis = 6;
314         public static final int ITEM_Object = 7;
315         public static final int ITEM_Uninitialized = 8;
316 
317         static verification_type_info read(ClassReader cr)
318                 throws IOException, InvalidStackMap {
319             int tag = cr.readUnsignedByte();
320             switch (tag) {
321             case ITEM_Top:
322             case ITEM_Integer:
323             case ITEM_Float:
324             case ITEM_Long:
325             case ITEM_Double:
326             case ITEM_Null:
327             case ITEM_UninitializedThis:
328                 return new verification_type_info(tag);
329 
330             case ITEM_Object:
331                 return new Object_variable_info(cr);
332 
333             case ITEM_Uninitialized:
334                 return new Uninitialized_variable_info(cr);
335 
336             default:
337                 throw new InvalidStackMap("unrecognized verification_type_info tag");
338             }
339         }
340 
341         protected verification_type_info(int tag) {
342             this.tag = tag;
343         }
344 
345         public int length() {
346             return 1;
347         }
348 
349         public final int tag;
350     }
351 
352     public static class Object_variable_info extends verification_type_info {
353         Object_variable_info(ClassReader cr) throws IOException {
354             super(ITEM_Object);
355             cpool_index = cr.readUnsignedShort();
356         }
357 
358         @Override
359         public int length() {
360             return super.length() + 2;
361         }
362 
363         public final int cpool_index;
364     }
365 
366     public static class Uninitialized_variable_info extends verification_type_info {
367         Uninitialized_variable_info(ClassReader cr) throws IOException {
368             super(ITEM_Uninitialized);
369             offset = cr.readUnsignedShort();
370         }
371 
372         @Override
373         public int length() {
374             return super.length() + 2;
375         }
376 
377         public final int offset;
378 
379     }
380 }