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