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 }