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