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 }