1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.bcel.classfile; 19 20 import java.io.DataInput; 21 import java.io.DataOutputStream; 22 import java.io.IOException; 23 import org.apache.bcel.Const; 24 25 /** 26 * This class represents a stack map entry recording the types of 27 * local variables and the the of stack items at a given byte code offset. 28 * See CLDC specification 5.3.1.2 29 * 30 * @version $Id$ 31 * @see StackMap 32 * @see StackMapType 33 */ 34 public final class StackMapEntry implements Node, Cloneable 35 { 36 37 private int frame_type; 38 private int byte_code_offset; 39 private StackMapType[] types_of_locals; 40 private StackMapType[] types_of_stack_items; 41 private ConstantPool constant_pool; 42 43 44 /** 45 * Construct object from input stream. 46 * 47 * @param input Input stream 48 * @throws IOException 49 */ StackMapEntry(final DataInput input, final ConstantPool constantPool)50 StackMapEntry(final DataInput input, final ConstantPool constantPool) throws IOException { 51 this(input.readByte() & 0xFF, -1, null, null, constantPool); 52 53 if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { 54 byte_code_offset = frame_type - Const.SAME_FRAME; 55 } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && 56 frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { 57 byte_code_offset = frame_type - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; 58 types_of_stack_items = new StackMapType[1]; 59 types_of_stack_items[0] = new StackMapType(input, constantPool); 60 } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 61 byte_code_offset = input.readShort(); 62 types_of_stack_items = new StackMapType[1]; 63 types_of_stack_items[0] = new StackMapType(input, constantPool); 64 } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { 65 byte_code_offset = input.readShort(); 66 } else if (frame_type == Const.SAME_FRAME_EXTENDED) { 67 byte_code_offset = input.readShort(); 68 } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { 69 byte_code_offset = input.readShort(); 70 final int number_of_locals = frame_type - 251; 71 types_of_locals = new StackMapType[number_of_locals]; 72 for (int i = 0; i < number_of_locals; i++) { 73 types_of_locals[i] = new StackMapType(input, constantPool); 74 } 75 } else if (frame_type == Const.FULL_FRAME) { 76 byte_code_offset = input.readShort(); 77 final int number_of_locals = input.readShort(); 78 types_of_locals = new StackMapType[number_of_locals]; 79 for (int i = 0; i < number_of_locals; i++) { 80 types_of_locals[i] = new StackMapType(input, constantPool); 81 } 82 final int number_of_stack_items = input.readShort(); 83 types_of_stack_items = new StackMapType[number_of_stack_items]; 84 for (int i = 0; i < number_of_stack_items; i++) { 85 types_of_stack_items[i] = new StackMapType(input, constantPool); 86 } 87 } else { 88 /* Can't happen */ 89 throw new ClassFormatException ("Invalid frame type found while parsing stack map table: " + frame_type); 90 } 91 } 92 93 /** 94 * DO NOT USE 95 * 96 * @param byteCodeOffset 97 * @param numberOfLocals NOT USED 98 * @param typesOfLocals array of {@link StackMapType}s of locals 99 * @param numberOfStackItems NOT USED 100 * @param typesOfStackItems array ot {@link StackMapType}s of stack items 101 * @param constantPool the constant pool 102 * @deprecated Since 6.0, use {@link #StackMapEntry(int, int, StackMapType[], StackMapType[], ConstantPool)} 103 * instead 104 */ 105 @java.lang.Deprecated StackMapEntry(final int byteCodeOffset, final int numberOfLocals, final StackMapType[] typesOfLocals, final int numberOfStackItems, final StackMapType[] typesOfStackItems, final ConstantPool constantPool)106 public StackMapEntry(final int byteCodeOffset, final int numberOfLocals, 107 final StackMapType[] typesOfLocals, final int numberOfStackItems, 108 final StackMapType[] typesOfStackItems, final ConstantPool constantPool) { 109 this.byte_code_offset = byteCodeOffset; 110 this.types_of_locals = typesOfLocals != null ? typesOfLocals : new StackMapType[0]; 111 this.types_of_stack_items = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0]; 112 this.constant_pool = constantPool; 113 } 114 115 /** 116 * Create an instance 117 * 118 * @param tag the frame_type to use 119 * @param byteCodeOffset 120 * @param typesOfLocals array of {@link StackMapType}s of locals 121 * @param typesOfStackItems array ot {@link StackMapType}s of stack items 122 * @param constantPool the constant pool 123 */ StackMapEntry(final int tag, final int byteCodeOffset, final StackMapType[] typesOfLocals, final StackMapType[] typesOfStackItems, final ConstantPool constantPool)124 public StackMapEntry(final int tag, final int byteCodeOffset, 125 final StackMapType[] typesOfLocals, 126 final StackMapType[] typesOfStackItems, final ConstantPool constantPool) { 127 this.frame_type = tag; 128 this.byte_code_offset = byteCodeOffset; 129 this.types_of_locals = typesOfLocals != null ? typesOfLocals : new StackMapType[0]; 130 this.types_of_stack_items = typesOfStackItems != null ? typesOfStackItems : new StackMapType[0]; 131 this.constant_pool = constantPool; 132 } 133 134 135 /** 136 * Dump stack map entry 137 * 138 * @param file Output file stream 139 * @throws IOException 140 */ dump( final DataOutputStream file )141 public final void dump( final DataOutputStream file ) throws IOException { 142 file.write(frame_type); 143 if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { 144 // nothing to be done 145 } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && 146 frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { 147 types_of_stack_items[0].dump(file); 148 } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 149 file.writeShort(byte_code_offset); 150 types_of_stack_items[0].dump(file); 151 } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { 152 file.writeShort(byte_code_offset); 153 } else if (frame_type == Const.SAME_FRAME_EXTENDED) { 154 file.writeShort(byte_code_offset); 155 } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { 156 file.writeShort(byte_code_offset); 157 for (final StackMapType type : types_of_locals) { 158 type.dump(file); 159 } 160 } else if (frame_type == Const.FULL_FRAME) { 161 file.writeShort(byte_code_offset); 162 file.writeShort(types_of_locals.length); 163 for (final StackMapType type : types_of_locals) { 164 type.dump(file); 165 } 166 file.writeShort(types_of_stack_items.length); 167 for (final StackMapType type : types_of_stack_items) { 168 type.dump(file); 169 } 170 } else { 171 /* Can't happen */ 172 throw new ClassFormatException ("Invalid Stack map table tag: " + frame_type); 173 } 174 } 175 176 177 /** 178 * @return String representation. 179 */ 180 @Override toString()181 public final String toString() { 182 final StringBuilder buf = new StringBuilder(64); 183 buf.append("("); 184 if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { 185 buf.append("SAME"); 186 } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && 187 frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { 188 buf.append("SAME_LOCALS_1_STACK"); 189 } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 190 buf.append("SAME_LOCALS_1_STACK_EXTENDED"); 191 } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { 192 buf.append("CHOP ").append(String.valueOf(251-frame_type)); 193 } else if (frame_type == Const.SAME_FRAME_EXTENDED) { 194 buf.append("SAME_EXTENDED"); 195 } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { 196 buf.append("APPEND ").append(String.valueOf(frame_type-251)); 197 } else if (frame_type == Const.FULL_FRAME) { 198 buf.append("FULL"); 199 } else { 200 buf.append("UNKNOWN (").append(frame_type).append(")"); 201 } 202 buf.append(", offset delta=").append(byte_code_offset); 203 if (types_of_locals.length > 0) { 204 buf.append(", locals={"); 205 for (int i = 0; i < types_of_locals.length; i++) { 206 buf.append(types_of_locals[i]); 207 if (i < types_of_locals.length - 1) { 208 buf.append(", "); 209 } 210 } 211 buf.append("}"); 212 } 213 if (types_of_stack_items.length > 0) { 214 buf.append(", stack items={"); 215 for (int i = 0; i < types_of_stack_items.length; i++) { 216 buf.append(types_of_stack_items[i]); 217 if (i < types_of_stack_items.length - 1) { 218 buf.append(", "); 219 } 220 } 221 buf.append("}"); 222 } 223 buf.append(")"); 224 return buf.toString(); 225 } 226 227 228 /** 229 * Calculate stack map entry size 230 * 231 */ getMapEntrySize()232 int getMapEntrySize() { 233 if (frame_type >= Const.SAME_FRAME && frame_type <= Const.SAME_FRAME_MAX) { 234 return 1; 235 } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && 236 frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { 237 return 1 + (types_of_stack_items[0].hasIndex() ? 3 : 1); 238 } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { 239 return 3 + (types_of_stack_items[0].hasIndex() ? 3 : 1); 240 } else if (frame_type >= Const.CHOP_FRAME && frame_type <= Const.CHOP_FRAME_MAX) { 241 return 3; 242 } else if (frame_type == Const.SAME_FRAME_EXTENDED) { 243 return 3; 244 } else if (frame_type >= Const.APPEND_FRAME && frame_type <= Const.APPEND_FRAME_MAX) { 245 int len = 3; 246 for (final StackMapType types_of_local : types_of_locals) { 247 len += types_of_local.hasIndex() ? 3 : 1; 248 } 249 return len; 250 } else if (frame_type == Const.FULL_FRAME) { 251 int len = 7; 252 for (final StackMapType types_of_local : types_of_locals) { 253 len += types_of_local.hasIndex() ? 3 : 1; 254 } 255 for (final StackMapType types_of_stack_item : types_of_stack_items) { 256 len += types_of_stack_item.hasIndex() ? 3 : 1; 257 } 258 return len; 259 } else { 260 throw new RuntimeException("Invalid StackMap frame_type: " + frame_type); 261 } 262 } 263 264 setFrameType( final int f )265 public void setFrameType( final int f ) { 266 if (f >= Const.SAME_FRAME && f <= Const.SAME_FRAME_MAX) { 267 byte_code_offset = f - Const.SAME_FRAME; 268 } else if (f >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && 269 f <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { 270 byte_code_offset = f - Const.SAME_LOCALS_1_STACK_ITEM_FRAME; 271 } else if (f == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock 272 } else if (f >= Const.CHOP_FRAME && f <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock 273 } else if (f == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock 274 } else if (f >= Const.APPEND_FRAME && f <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock 275 } else if (f == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock 276 } else { 277 throw new RuntimeException("Invalid StackMap frame_type"); 278 } 279 frame_type = f; 280 } 281 282 getFrameType()283 public int getFrameType() { 284 return frame_type; 285 } 286 287 setByteCodeOffset( final int new_offset )288 public void setByteCodeOffset( final int new_offset ) { 289 if (new_offset < 0 || new_offset > 32767) { 290 throw new RuntimeException("Invalid StackMap offset: " + new_offset); 291 } 292 293 if (frame_type >= Const.SAME_FRAME && 294 frame_type <= Const.SAME_FRAME_MAX) { 295 if (new_offset > Const.SAME_FRAME_MAX) { 296 frame_type = Const.SAME_FRAME_EXTENDED; 297 } else { 298 frame_type = new_offset; 299 } 300 } else if (frame_type >= Const.SAME_LOCALS_1_STACK_ITEM_FRAME && 301 frame_type <= Const.SAME_LOCALS_1_STACK_ITEM_FRAME_MAX) { 302 if (new_offset > Const.SAME_FRAME_MAX) { 303 frame_type = Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 304 } else { 305 frame_type = Const.SAME_LOCALS_1_STACK_ITEM_FRAME + new_offset; 306 } 307 } else if (frame_type == Const.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock 308 } else if (frame_type >= Const.CHOP_FRAME && 309 frame_type <= Const.CHOP_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock 310 } else if (frame_type == Const.SAME_FRAME_EXTENDED) { // CHECKSTYLE IGNORE EmptyBlock 311 } else if (frame_type >= Const.APPEND_FRAME && 312 frame_type <= Const.APPEND_FRAME_MAX) { // CHECKSTYLE IGNORE EmptyBlock 313 } else if (frame_type == Const.FULL_FRAME) { // CHECKSTYLE IGNORE EmptyBlock 314 } else { 315 throw new RuntimeException("Invalid StackMap frame_type: " + frame_type); 316 } 317 byte_code_offset = new_offset; 318 } 319 320 321 /** 322 * Update the distance (as an offset delta) from this StackMap 323 * entry to the next. Note that this might cause the the 324 * frame type to change. Note also that delta may be negative. 325 * 326 * @param delta offset delta 327 */ updateByteCodeOffset(final int delta)328 public void updateByteCodeOffset(final int delta) { 329 setByteCodeOffset(byte_code_offset + delta); 330 } 331 332 getByteCodeOffset()333 public int getByteCodeOffset() { 334 return byte_code_offset; 335 } 336 337 338 /** 339 * 340 * @deprecated since 6.0 341 */ 342 @java.lang.Deprecated setNumberOfLocals( final int n )343 public void setNumberOfLocals( final int n ) { // TODO unused 344 } 345 346 getNumberOfLocals()347 public int getNumberOfLocals() { 348 return types_of_locals.length; 349 } 350 351 setTypesOfLocals( final StackMapType[] types )352 public void setTypesOfLocals( final StackMapType[] types ) { 353 types_of_locals = types != null ? types : new StackMapType[0]; 354 } 355 356 getTypesOfLocals()357 public StackMapType[] getTypesOfLocals() { 358 return types_of_locals; 359 } 360 361 362 /** 363 * 364 * @deprecated since 6.0 365 */ 366 @java.lang.Deprecated setNumberOfStackItems( final int n )367 public void setNumberOfStackItems( final int n ) { // TODO unused 368 } 369 370 getNumberOfStackItems()371 public int getNumberOfStackItems() { 372 return types_of_stack_items.length; 373 } 374 375 setTypesOfStackItems( final StackMapType[] types )376 public void setTypesOfStackItems( final StackMapType[] types ) { 377 types_of_stack_items = types != null ? types : new StackMapType[0]; 378 } 379 380 getTypesOfStackItems()381 public StackMapType[] getTypesOfStackItems() { 382 return types_of_stack_items; 383 } 384 385 386 /** 387 * @return deep copy of this object 388 */ copy()389 public StackMapEntry copy() { 390 StackMapEntry e; 391 try { 392 e = (StackMapEntry) clone(); 393 } catch (final CloneNotSupportedException ex) { 394 throw new Error("Clone Not Supported"); 395 } 396 397 e.types_of_locals = new StackMapType[types_of_locals.length]; 398 for (int i = 0; i < types_of_locals.length; i++) { 399 e.types_of_locals[i] = types_of_locals[i].copy(); 400 } 401 e.types_of_stack_items = new StackMapType[types_of_stack_items.length]; 402 for (int i = 0; i < types_of_stack_items.length; i++) { 403 e.types_of_stack_items[i] = types_of_stack_items[i].copy(); 404 } 405 return e; 406 } 407 408 409 /** 410 * Called by objects that are traversing the nodes of the tree implicitely 411 * defined by the contents of a Java class. I.e., the hierarchy of methods, 412 * fields, attributes, etc. spawns a tree of objects. 413 * 414 * @param v Visitor object 415 */ 416 @Override accept( final Visitor v )417 public void accept( final Visitor v ) { 418 v.visitStackMapEntry(this); 419 } 420 421 422 /** 423 * @return Constant pool used by this object. 424 */ getConstantPool()425 public final ConstantPool getConstantPool() { 426 return constant_pool; 427 } 428 429 430 /** 431 * @param constant_pool Constant pool to be used for this object. 432 */ setConstantPool( final ConstantPool constant_pool )433 public final void setConstantPool( final ConstantPool constant_pool ) { 434 this.constant_pool = constant_pool; 435 } 436 } 437