1 /*
  2  * Copyright (c) 2007, 2025, 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_entry[number_of_entries];
 51         for (int i = 0; i < number_of_entries; i++)
 52             entries[i] = stack_map_entry.read(cr);
 53     }
 54 
 55     public StackMapTable_attribute(ConstantPool constant_pool, stack_map_entry[] entries)
 56             throws ConstantPoolException {
 57         this(constant_pool.getUTF8Index(Attribute.StackMapTable), entries);
 58     }
 59 
 60     public StackMapTable_attribute(int name_index, stack_map_entry[] 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_entry[] entries) {
 71         int n = 2;
 72         for (stack_map_entry entry: entries)
 73             n += entry.length();
 74         return n;
 75     }
 76 
 77     public final int number_of_entries;
 78     public final stack_map_entry entries[];
 79 
 80     public abstract static class stack_map_entry {
 81         static stack_map_entry read(ClassReader cr)
 82                 throws IOException, InvalidStackMap {
 83             int entry_type = cr.readUnsignedByte();
 84             if (entry_type <= 63)
 85                 return new same_frame(entry_type);
 86             else if (entry_type <= 127)
 87                 return new same_locals_1_stack_item_frame(entry_type, cr);
 88             else if (entry_type <= 245)
 89                 throw new Error("unknown frame_type " + entry_type);
 90             else if (entry_type == 246)
 91                 return new assert_unset_fields(entry_type, cr);
 92             else if (entry_type == 247)
 93                 return new same_locals_1_stack_item_frame_extended(entry_type, cr);
 94             else if (entry_type <= 250)
 95                 return new chop_frame(entry_type, cr);
 96             else if (entry_type == 251)
 97                 return new same_frame_extended(entry_type, cr);
 98             else if (entry_type <= 254)
 99                 return new append_frame(entry_type, cr);
100             else
101                 return new full_frame(entry_type, cr);
102         }
103 
104         protected stack_map_entry(int entry_type) {
105             this.entry_type = entry_type;
106         }
107 
108         public int length() {
109             return 1;
110         }
111 
112         public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
113 
114         public final int entry_type;
115 
116         public 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             R visit_assert_unset_fields(assert_unset_fields frame, P p);
125         }
126     }
127 
128     public static class same_frame extends stack_map_entry {
129         same_frame(int entry_type) {
130             super(entry_type);
131         }
132 
133         public <R, D> R accept(Visitor<R, D> visitor, D data) {
134             return visitor.visit_same_frame(this, data);
135         }
136     }
137 
138     public static class same_locals_1_stack_item_frame extends stack_map_entry {
139         same_locals_1_stack_item_frame(int entry_type, ClassReader cr)
140                 throws IOException, InvalidStackMap {
141             super(entry_type);
142             stack = new verification_type_info[1];
143             stack[0] = verification_type_info.read(cr);
144         }
145 
146         @Override
147         public int length() {
148             return super.length() + stack[0].length();
149         }
150 
151         public <R, D> R accept(Visitor<R, D> visitor, D data) {
152             return visitor.visit_same_locals_1_stack_item_frame(this, data);
153         }
154 
155         public final verification_type_info[] stack;
156     }
157 
158     public static class same_locals_1_stack_item_frame_extended extends stack_map_entry {
159         same_locals_1_stack_item_frame_extended(int entry_type, ClassReader cr)
160                 throws IOException, InvalidStackMap {
161             super(entry_type);
162             offset_delta = cr.readUnsignedShort();
163             stack = new verification_type_info[1];
164             stack[0] = verification_type_info.read(cr);
165         }
166 
167         @Override
168         public int length() {
169             return super.length() + 2 + stack[0].length();
170         }
171 
172         public <R, D> R accept(Visitor<R, D> visitor, D data) {
173             return visitor.visit_same_locals_1_stack_item_frame_extended(this, data);
174         }
175 
176         public final int offset_delta;
177         public final verification_type_info[] stack;
178     }
179 
180     public static class chop_frame extends stack_map_entry {
181         chop_frame(int entry_type, ClassReader cr) throws IOException {
182             super(entry_type);
183             offset_delta = cr.readUnsignedShort();
184         }
185 
186         @Override
187         public int length() {
188             return super.length() + 2;
189         }
190 
191         public <R, D> R accept(Visitor<R, D> visitor, D data) {
192             return visitor.visit_chop_frame(this, data);
193         }
194 
195         public final int offset_delta;
196     }
197 
198     public static class same_frame_extended extends stack_map_entry {
199         same_frame_extended(int entry_type, ClassReader cr) throws IOException {
200             super(entry_type);
201             offset_delta = cr.readUnsignedShort();
202         }
203 
204         @Override
205         public int length() {
206             return super.length() + 2;
207         }
208 
209         public <R, D> R accept(Visitor<R, D> visitor, D data) {
210             return visitor.visit_same_frame_extended(this, data);
211         }
212 
213         public final int offset_delta;
214     }
215 
216     public static class append_frame extends stack_map_entry {
217         append_frame(int entry_type, ClassReader cr)
218                 throws IOException, InvalidStackMap {
219             super(entry_type);
220             offset_delta = cr.readUnsignedShort();
221             locals = new verification_type_info[entry_type - 251];
222             for (int i = 0; i < locals.length; i++)
223                 locals[i] = verification_type_info.read(cr);
224         }
225 
226         @Override
227         public int length() {
228             int n = super.length() + 2;
229             for (verification_type_info local: locals)
230                 n += local.length();
231             return n;
232         }
233 
234         public <R, D> R accept(Visitor<R, D> visitor, D data) {
235             return visitor.visit_append_frame(this, data);
236         }
237 
238         public final int offset_delta;
239         public final verification_type_info[] locals;
240     }
241 
242     public static class full_frame extends stack_map_entry {
243         full_frame(int entry_type, ClassReader cr)
244                 throws IOException, InvalidStackMap {
245             super(entry_type);
246             offset_delta = cr.readUnsignedShort();
247             number_of_locals = cr.readUnsignedShort();
248             locals = new verification_type_info[number_of_locals];
249             for (int i = 0; i < locals.length; i++)
250                 locals[i] = verification_type_info.read(cr);
251             number_of_stack_items = cr.readUnsignedShort();
252             stack = new verification_type_info[number_of_stack_items];
253             for (int i = 0; i < stack.length; i++)
254                 stack[i] = verification_type_info.read(cr);
255         }
256 
257         @Override
258         public int length() {
259             int n = super.length() + 2;
260             for (verification_type_info local: locals)
261                 n += local.length();
262             n += 2;
263             for (verification_type_info item: stack)
264                 n += item.length();
265             return n;
266         }
267 
268         public <R, D> R accept(Visitor<R, D> visitor, D data) {
269             return visitor.visit_full_frame(this, data);
270         }
271 
272         public final int offset_delta;
273         public final int number_of_locals;
274         public final verification_type_info[] locals;
275         public final int number_of_stack_items;
276         public final verification_type_info[] stack;
277     }
278 
279     public static class assert_unset_fields extends stack_map_entry {
280         assert_unset_fields(int entry_type, ClassReader cr) throws IOException {
281             super(entry_type);
282             number_of_unset_fields = cr.readUnsignedShort();
283             unset_fields = new int[number_of_unset_fields];
284             for (int i = 0; i < number_of_unset_fields; i++) {
285                 unset_fields[i] = cr.readUnsignedShort();
286             }
287         }
288 
289         public <R, D> R accept(Visitor<R, D> visitor, D data) {
290             return visitor.visit_assert_unset_fields(this, data);
291         }
292 
293         public final int number_of_unset_fields;
294         public final int[] unset_fields;
295     }
296 
297     public static class verification_type_info {
298         public static final int ITEM_Top = 0;
299         public static final int ITEM_Integer = 1;
300         public static final int ITEM_Float = 2;
301         public static final int ITEM_Long = 4;
302         public static final int ITEM_Double = 3;
303         public static final int ITEM_Null = 5;
304         public static final int ITEM_UninitializedThis = 6;
305         public static final int ITEM_Object = 7;
306         public static final int ITEM_Uninitialized = 8;
307 
308         static verification_type_info read(ClassReader cr)
309                 throws IOException, InvalidStackMap {
310             int tag = cr.readUnsignedByte();
311             switch (tag) {
312             case ITEM_Top:
313             case ITEM_Integer:
314             case ITEM_Float:
315             case ITEM_Long:
316             case ITEM_Double:
317             case ITEM_Null:
318             case ITEM_UninitializedThis:
319                 return new verification_type_info(tag);
320 
321             case ITEM_Object:
322                 return new Object_variable_info(cr);
323 
324             case ITEM_Uninitialized:
325                 return new Uninitialized_variable_info(cr);
326 
327             default:
328                 throw new InvalidStackMap("unrecognized verification_type_info tag");
329             }
330         }
331 
332         protected verification_type_info(int tag) {
333             this.tag = tag;
334         }
335 
336         public int length() {
337             return 1;
338         }
339 
340         public final int tag;
341     }
342 
343     public static class Object_variable_info extends verification_type_info {
344         Object_variable_info(ClassReader cr) throws IOException {
345             super(ITEM_Object);
346             cpool_index = cr.readUnsignedShort();
347         }
348 
349         @Override
350         public int length() {
351             return super.length() + 2;
352         }
353 
354         public final int cpool_index;
355     }
356 
357     public static class Uninitialized_variable_info extends verification_type_info {
358         Uninitialized_variable_info(ClassReader cr) throws IOException {
359             super(ITEM_Uninitialized);
360             offset = cr.readUnsignedShort();
361         }
362 
363         @Override
364         public int length() {
365             return super.length() + 2;
366         }
367 
368         public final int offset;
369 
370     }
371 }