1 /** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2005 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package org.objectweb.asm.attrs; 31 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.List; 35 36 import org.objectweb.asm.Attribute; 37 import org.objectweb.asm.ByteVector; 38 import org.objectweb.asm.ClassReader; 39 import org.objectweb.asm.ClassWriter; 40 import org.objectweb.asm.Label; 41 import org.objectweb.asm.Opcodes; 42 import org.objectweb.asm.Type; 43 44 /** 45 * The stack map attribute is used during the process of verification by 46 * typechecking (§4.11.1). <br> <br> A stack map attribute consists of zero or 47 * more stack map frames. Each stack map frame specifies (either explicitly or 48 * implicitly) a bytecode offset, the verification types (§4.11.1) for the local 49 * variables, and the verification types for the operand stack. <br> <br> The 50 * type checker deals with and manipulates the expected types of a method's 51 * local variables and operand stack. Throughout this section, a location refers 52 * to either a single local variable or to a single operand stack entry. <br> 53 * <br> We will use the terms stack frame map and type state interchangeably to 54 * describe a mapping from locations in the operand stack and local variables of 55 * a method to verification types. We will usually use the term stack frame map 56 * when such a mapping is provided in the class file, and the term type state 57 * when the mapping is inferred by the type checker. <br> <br> If a method's 58 * Code attribute does not have a StackMapTable attribute, it has an implicit 59 * stack map attribute. This implicit stack map attribute is equivalent to a 60 * StackMapTable attribute with number_of_entries equal to zero. A method's Code 61 * attribute may have at most one StackMapTable attribute, otherwise a 62 * java.lang.ClassFormatError is thrown. <br> <br> The format of the stack map 63 * in the class file is given below. In the following, if the length of the 64 * method's byte code is 65535 or less, then uoffset represents the type u2; 65 * otherwise uoffset represents the type u4. If the maximum number of local 66 * variables for the method is 65535 or less, then <code>ulocalvar</code> 67 * represents the type u2; otherwise ulocalvar represents the type u4. If the 68 * maximum size of the operand stack is 65535 or less, then <code>ustack</code> 69 * represents the type u2; otherwise ustack represents the type u4. 70 * 71 * <pre> 72 * stack_map { // attribute StackMapTable 73 * u2 attribute_name_index; 74 * u4 attribute_length 75 * uoffset number_of_entries; 76 * stack_map_frame entries[number_of_entries]; 77 * } 78 * </pre> 79 * 80 * Each stack_map_frame structure specifies the type state at a particular byte 81 * code offset. Each frame type specifies (explicitly or implicitly) a value, 82 * offset_delta, that is used to calulate the actual byte code offset at which 83 * it applies. The byte code offset at which the frame applies is given by 84 * adding <code>1 + offset_delta</code> to the <code>offset</code> of the 85 * previous frame, unless the previous frame is the initial frame of the method, 86 * in which case the byte code offset is <code>offset_delta</code>. <br> <br> 87 * <i>Note that the length of the byte codes is not the same as the length of 88 * the Code attribute. The byte codes are embedded in the Code attribute, along 89 * with other information.</i> <br> <br> By using an offset delta rather than 90 * the actual byte code offset we ensure, by definition, that stack map frames 91 * are in the correctly sorted order. Furthermore, by consistently using the 92 * formula <code>offset_delta + 1</code> for all explicit frames, we guarantee 93 * the absence of duplicates. <br> <br> All frame types, even full_frame, rely 94 * on the previous frame for some of their semantics. This raises the question 95 * of what is the very first frame? The initial frame is implicit, and computed 96 * from the method descriptor. See the Prolog code for methodInitialStacFrame. 97 * <br> <br> The stack_map_frame structure consists of a one-byte tag followed 98 * by zero or more bytes, giving more information, depending upon the tag. <br> 99 * <br> A stack map frame may belong to one of several frame types 100 * 101 * <pre> 102 * union stack_map_frame { 103 * same_frame; 104 * same_locals_1_stack_item_frame; 105 * chop_frame; 106 * same_frame_extended; 107 * append_frame; 108 * full_frame; 109 * } 110 * </pre> 111 * 112 * The frame type same_frame is represented by tags in the range [0-63]. If the 113 * frame type is same_frame, it means the frame has exactly the same locals as 114 * the previous stack map frame and that the number of stack items is zero. The 115 * offset_delta value for the frame is the value of the tag field, frame_type. 116 * The form of such a frame is then: 117 * 118 * <pre> 119 * same_frame { 120 * u1 frame_type = SAME; // 0-63 121 * } 122 * </pre> 123 * 124 * The frame type same_locals_1_stack_item_frame is represented by tags in the 125 * range [64, 127]. If the frame_type is same_locals_1_stack_item_frame, it 126 * means the frame has exactly the same locals as the previous stack map frame 127 * and that the number of stack items is 1. The offset_delta value for the frame 128 * is the value (frame_type - 64). There is a verification_type_info following 129 * the frame_type for the one stack item. The form of such a frame is then: 130 * 131 * <pre> 132 * same_locals_1_stack_item_frame { 133 * u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127 134 * verification_type_info stack[1]; 135 * } 136 * </pre> 137 * 138 * Tags in the range [128-247] are reserved for future use. <br> <br> The frame 139 * type chop_frame is represented by tags in the range [248-250]. If the 140 * frame_type is chop_frame, it means that the current locals are the same as 141 * the locals in the previous frame, except that the k last locals are absent. 142 * The value of k is given by the formula 251-frame_type. <br> <br> The form of 143 * such a frame is then: 144 * 145 * <pre> 146 * chop_frame { 147 * u1 frame_type=CHOP; // 248-250 148 * uoffset offset_delta; 149 * } 150 * </pre> 151 * 152 * The frame type same_frame_extended is represented by the tag value 251. If 153 * the frame type is same_frame_extended, it means the frame has exactly the 154 * same locals as the previous stack map frame and that the number of stack 155 * items is zero. The form of such a frame is then: 156 * 157 * <pre> 158 * same_frame_extended { 159 * u1 frame_type = SAME_FRAME_EXTENDED; // 251 160 * uoffset offset_delta; 161 * } 162 * </pre> 163 * 164 * The frame type append_frame is represented by tags in the range [252-254]. If 165 * the frame_type is append_frame, it means that the current locals are the same 166 * as the locals in the previous frame, except that k additional locals are 167 * defined. The value of k is given by the formula frame_type-251. <br> <br> The 168 * form of such a frame is then: 169 * 170 * <pre> 171 * append_frame { 172 * u1 frame_type =APPEND; // 252-254 173 * uoffset offset_delta; 174 * verification_type_info locals[frame_type -251]; 175 * } 176 * </pre> 177 * 178 * The 0th entry in locals represents the type of the first additional local 179 * variable. If locals[M] represents local variable N, then locals[M+1] 180 * represents local variable N+1 if locals[M] is one of Top_variable_info, 181 * Integer_variable_info, Float_variable_info, Null_variable_info, 182 * UninitializedThis_variable_info, Object_variable_info, or 183 * Uninitialized_variable_info, otherwise locals[M+1] represents local variable 184 * N+2. It is an error if, for any index i, locals[i] represents a local 185 * variable whose index is greater than the maximum number of local variables 186 * for the method. <br> <br> The frame type full_frame is represented by the tag 187 * value 255. The form of such a frame is then: 188 * 189 * <pre> 190 * full_frame { 191 * u1 frame_type = FULL_FRAME; // 255 192 * uoffset offset_delta; 193 * ulocalvar number_of_locals; 194 * verification_type_info locals[number_of_locals]; 195 * ustack number_of_stack_items; 196 * verification_type_info stack[number_of_stack_items]; 197 * } 198 * </pre> 199 * 200 * The 0th entry in locals represents the type of local variable 0. If locals[M] 201 * represents local variable N, then locals[M+1] represents local variable N+1 202 * if locals[M] is one of Top_variable_info, Integer_variable_info, 203 * Float_variable_info, Null_variable_info, UninitializedThis_variable_info, 204 * Object_variable_info, or Uninitialized_variable_info, otherwise locals[M+1] 205 * represents local variable N+2. It is an error if, for any index i, locals[i] 206 * represents a local variable whose index is greater than the maximum number of 207 * local variables for the method. <br> <br> The 0th entry in stack represents 208 * the type of the bottom of the stack, and subsequent entries represent types 209 * of stack elements closer to the top of the operand stack. We shall refer to 210 * the bottom element of the stack as stack element 0, and to subsequent 211 * elements as stack element 1, 2 etc. If stack[M] represents stack element N, 212 * then stack[M+1] represents stack element N+1 if stack[M] is one of 213 * Top_variable_info, Integer_variable_info, Float_variable_info, 214 * Null_variable_info, UninitializedThis_variable_info, Object_variable_info, or 215 * Uninitialized_variable_info, otherwise stack[M+1] represents stack element 216 * N+2. It is an error if, for any index i, stack[i] represents a stack entry 217 * whose index is greater than the maximum operand stack size for the method. 218 * <br> <br> We say that an instruction in the byte code has a corresponding 219 * stack map frame if the offset in the offset field of the stack map frame is 220 * the same as the offset of the instruction in the byte codes. <br> <br> The 221 * verification_type_info structure consists of a one-byte tag followed by zero 222 * or more bytes, giving more information about the tag. Each 223 * verification_type_info structure specifies the verification type of one or 224 * two locations. 225 * 226 * <pre> 227 * union verification_type_info { 228 * Top_variable_info; 229 * Integer_variable_info; 230 * Float_variable_info; 231 * Long_variable_info; 232 * Double_variable_info; 233 * Null_variable_info; 234 * UninitializedThis_variable_info; 235 * Object_variable_info; 236 * Uninitialized_variable_info; 237 * } 238 * </pre> 239 * 240 * The Top_variable_info type indicates that the local variable has the 241 * verification type top (T.) 242 * 243 * <pre> 244 * Top_variable_info { 245 * u1 tag = ITEM_Top; // 0 246 * } 247 * </pre> 248 * 249 * The Integer_variable_info type indicates that the location contains the 250 * verification type int. 251 * 252 * <pre> 253 * Integer_variable_info { 254 * u1 tag = ITEM_Integer; // 1 255 * } 256 * </pre> 257 * 258 * The Float_variable_info type indicates that the location contains the 259 * verification type float. 260 * 261 * <pre> 262 * Float_variable_info { 263 * u1 tag = ITEM_Float; // 2 264 * } 265 * </pre> 266 * 267 * The Long_variable_info type indicates that the location contains the 268 * verification type long. If the location is a local variable, then: 269 * 270 * <ul> <li>It must not be the local variable with the highest index.</li> 271 * <li>The next higher numbered local variable contains the verification type 272 * T.</li> </ul> 273 * 274 * If the location is an operand stack entry, then: 275 * 276 * <ul> <li>The current location must not be the topmost location of the 277 * operand stack.</li> <li>the next location closer to the top of the operand 278 * stack contains the verification type T.</li> </ul> 279 * 280 * This structure gives the contents of two locations in the operand stack or in 281 * the local variables. 282 * 283 * <pre> 284 * Long_variable_info { 285 * u1 tag = ITEM_Long; // 4 286 * } 287 * </pre> 288 * 289 * The Double_variable_info type indicates that the location contains the 290 * verification type double. If the location is a local variable, then: 291 * 292 * <ul> <li>It must not be the local variable with the highest index.</li> 293 * <li>The next higher numbered local variable contains the verification type 294 * T. <li> </ul> 295 * 296 * If the location is an operand stack entry, then: 297 * 298 * <ul> <li>The current location must not be the topmost location of the 299 * operand stack.</li> <li>the next location closer to the top of the operand 300 * stack contains the verification type T.</li> </ul> 301 * 302 * This structure gives the contents of two locations in in the operand stack or 303 * in the local variables. 304 * 305 * <pre> 306 * Double_variable_info { 307 * u1 tag = ITEM_Double; // 3 308 * } 309 * </pre> 310 * 311 * The Null_variable_info type indicates that location contains the verification 312 * type null. 313 * 314 * <pre> 315 * Null_variable_info { 316 * u1 tag = ITEM_Null; // 5 317 * } 318 * </pre> 319 * 320 * The UninitializedThis_variable_info type indicates that the location contains 321 * the verification type uninitializedThis. 322 * 323 * <pre> 324 * UninitializedThis_variable_info { 325 * u1 tag = ITEM_UninitializedThis; // 6 326 * } 327 * </pre> 328 * 329 * The Object_variable_info type indicates that the location contains an 330 * instance of the class referenced by the constant pool entry. 331 * 332 * <pre> 333 * Object_variable_info { 334 * u1 tag = ITEM_Object; // 7 335 * u2 cpool_index; 336 * } 337 * </pre> 338 * 339 * The Uninitialized_variable_info indicates that the location contains the 340 * verification type uninitialized(offset). The offset item indicates the offset 341 * of the new instruction that created the object being stored in the location. 342 * 343 * <pre> 344 * Uninitialized_variable_info { 345 * u1 tag = ITEM_Uninitialized // 8 346 * uoffset offset; 347 * } 348 * </pre> 349 * 350 * @see "ClassFileFormat-Java6.fm Page 138 Friday, April 15, 2005 3:22 PM" 351 * 352 * @author Eugene Kuleshov 353 */ 354 public class StackMapTableAttribute extends Attribute { 355 /** 356 * Frame has exactly the same locals as the previous stack map frame and 357 * number of stack items is zero. 358 */ 359 public static final int SAME_FRAME = 0; // to 63 (0-3f) 360 361 /** 362 * Frame has exactly the same locals as the previous stack map frame and 363 * number of stack items is 1 364 */ 365 public static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 366 367 // (40-7f) 368 369 /** 370 * Reserved for future use 371 */ 372 public static final int RESERVED = 128; 373 374 /** 375 * Frame has exactly the same locals as the previous stack map frame and 376 * number of stack items is 1. Offset is bigger then 63; 377 */ 378 public static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 379 380 /** 381 * Frame where current locals are the same as the locals in the previous 382 * frame, except that the k last locals are absent. The value of k is given 383 * by the formula 251-frame_type. 384 */ 385 public static final int CHOP_FRAME = 248; // to 250 (f8-fA) 386 387 /** 388 * Frame has exactly the same locals as the previous stack map frame and 389 * number of stack items is zero. Offset is bigger then 63; 390 */ 391 public static final int SAME_FRAME_EXTENDED = 251; // fb 392 393 /** 394 * Frame where current locals are the same as the locals in the previous 395 * frame, except that k additional locals are defined. The value of k is 396 * given by the formula frame_type-251. 397 */ 398 public static final int APPEND_FRAME = 252; // to 254 // fc-fe 399 400 /** 401 * Full frame 402 */ 403 public static final int FULL_FRAME = 255; // ff 404 405 private static final int MAX_SHORT = 65535; 406 407 /** 408 * A <code>List</code> of <code>StackMapFrame</code> instances. 409 */ 410 private List frames; 411 412 public StackMapTableAttribute() { 413 super("StackMapTable"); 414 } 415 416 public StackMapTableAttribute(List frames) { 417 this(); 418 this.frames = frames; 419 } 420 421 public List getFrames() { 422 return frames; 423 } 424 425 public StackMapFrame getFrame(Label label) { 426 for (int i = 0; i < frames.size(); i++) { 427 StackMapFrame frame = (StackMapFrame) frames.get(i); 428 if (frame.label == label) { 429 return frame; 430 } 431 } 432 return null; 433 } 434 435 public boolean isUnknown() { 436 return false; 437 } 438 439 public boolean isCodeAttribute() { 440 return true; 441 } 442 443 protected Attribute read( 444 ClassReader cr, 445 int off, 446 int len, 447 char[] buf, 448 int codeOff, 449 Label[] labels) 450 { 451 452 ArrayList frames = new ArrayList(); 453 454 // note that this is not the size of Code attribute 455 boolean isExtCodeSize = cr.readInt(codeOff + 4) > MAX_SHORT; 456 boolean isExtLocals = cr.readUnsignedShort(codeOff + 2) > MAX_SHORT; 457 boolean isExtStack = cr.readUnsignedShort(codeOff) > MAX_SHORT; 458 459 int offset = 0; 460 461 int methodOff = getMethodOff(cr, codeOff, buf); 462 StackMapFrame frame = new StackMapFrame(getLabel(offset, labels), 463 calculateLocals(cr.readClass(cr.header + 2, buf), // owner 464 cr.readUnsignedShort(methodOff), // method access 465 cr.readUTF8(methodOff + 2, buf), // method name 466 cr.readUTF8(methodOff + 4, buf)), // method desc 467 Collections.EMPTY_LIST); 468 frames.add(frame); 469 470 // System.err.println( cr.readUTF8( methodOff + 2, buf)); 471 // System.err.println( offset +" delta:" + 0 +" : "+ frame); 472 473 int size; 474 if (isExtCodeSize) { 475 size = cr.readInt(off); 476 off += 4; 477 } else { 478 size = cr.readUnsignedShort(off); 479 off += 2; 480 } 481 482 for (; size > 0; size--) { 483 int tag = cr.readByte(off); // & 0xff; 484 off++; 485 486 List stack; 487 List locals; 488 489 int offsetDelta; 490 if (tag < SAME_LOCALS_1_STACK_ITEM_FRAME) { // SAME_FRAME 491 offsetDelta = tag; 492 493 locals = new ArrayList(frame.locals); 494 stack = Collections.EMPTY_LIST; 495 496 } else if (tag < RESERVED) { // SAME_LOCALS_1_STACK_ITEM_FRAME 497 offsetDelta = tag - SAME_LOCALS_1_STACK_ITEM_FRAME; 498 499 locals = new ArrayList(frame.locals); 500 stack = new ArrayList(); 501 // read verification_type_info stack[1]; 502 off = readType(stack, isExtCodeSize, cr, off, labels, buf); 503 504 } else { 505 if (isExtCodeSize) { 506 offsetDelta = cr.readInt(off); 507 off += 4; 508 } else { 509 offsetDelta = cr.readUnsignedShort(off); 510 off += 2; 511 } 512 513 if (tag == SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { // SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED 514 locals = new ArrayList(frame.locals); 515 stack = new ArrayList(); 516 // read verification_type_info stack[1]; 517 off = readType(stack, isExtCodeSize, cr, off, labels, buf); 518 519 } else if (tag >= CHOP_FRAME && tag < SAME_FRAME_EXTENDED) { // CHOP_FRAME 520 stack = Collections.EMPTY_LIST; 521 522 int k = SAME_FRAME_EXTENDED - tag; 523 // copy locals from prev frame and chop last k 524 locals = new ArrayList(frame.locals.subList(0, 525 frame.locals.size() - k)); 526 527 } else if (tag == SAME_FRAME_EXTENDED) { // SAME_FRAME_EXTENDED 528 stack = Collections.EMPTY_LIST; 529 locals = new ArrayList(frame.locals); 530 531 } else if ( /* tag>=APPEND && */tag < FULL_FRAME) { // APPEND_FRAME 532 stack = Collections.EMPTY_LIST; 533 534 // copy locals from prev frame and append new k 535 locals = new ArrayList(frame.locals); 536 for (int k = tag - SAME_FRAME_EXTENDED; k > 0; k--) { 537 off = readType(locals, 538 isExtCodeSize, 539 cr, 540 off, 541 labels, 542 buf); 543 } 544 545 } else if (tag == FULL_FRAME) { // FULL_FRAME 546 // read verification_type_info locals[number_of_locals]; 547 locals = new ArrayList(); 548 off = readTypes(locals, 549 isExtLocals, 550 isExtCodeSize, 551 cr, 552 off, 553 labels, 554 buf); 555 556 // read verification_type_info stack[number_of_stack_items]; 557 stack = new ArrayList(); 558 off = readTypes(stack, 559 isExtStack, 560 isExtCodeSize, 561 cr, 562 off, 563 labels, 564 buf); 565 566 } else { 567 throw new RuntimeException("Unknown frame type " + tag 568 + " after offset " + offset); 569 570 } 571 } 572 573 offset += offsetDelta; 574 575 Label offsetLabel = getLabel(offset, labels); 576 577 frame = new StackMapFrame(offsetLabel, locals, stack); 578 frames.add(frame); 579 // System.err.println( tag +" " + offset +" delta:" + offsetDelta + 580 // " frameType:"+ frameType+" : "+ frame); 581 582 offset++; 583 } 584 585 return new StackMapTableAttribute(frames); 586 } 587 588 protected ByteVector write( 589 ClassWriter cw, 590 byte[] code, 591 int len, 592 int maxStack, 593 int maxLocals) 594 { 595 ByteVector bv = new ByteVector(); 596 // TODO verify this value (MAX_SHORT) 597 boolean isExtCodeSize = code != null && code.length > MAX_SHORT; 598 writeSize(frames.size() - 1, bv, isExtCodeSize); 599 600 if (frames.size() < 2) { 601 return bv; 602 } 603 604 boolean isExtLocals = maxLocals > MAX_SHORT; 605 boolean isExtStack = maxStack > MAX_SHORT; 606 607 // skip the first frame 608 StackMapFrame frame = (StackMapFrame) frames.get(0); 609 List locals = frame.locals; 610 int offset = frame.label.getOffset(); 611 612 for (int i = 1; i < frames.size(); i++) { 613 frame = (StackMapFrame) frames.get(i); 614 615 List clocals = frame.locals; 616 List cstack = frame.stack; 617 int coffset = frame.label.getOffset(); 618 619 int clocalsSize = clocals.size(); 620 int cstackSize = cstack.size(); 621 622 int localsSize = locals.size(); 623 624 int delta = coffset - offset; 625 626 int type = FULL_FRAME; 627 int k = 0; 628 if (cstackSize == 0) { 629 k = clocalsSize - localsSize; 630 switch (k) { 631 case -3: 632 case -2: 633 case -1: 634 type = CHOP_FRAME; // CHOP or FULL 635 localsSize = clocalsSize; // for full_frame check 636 break; 637 638 case 0: 639 // SAME, SAME_EXTENDED or FULL 640 type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; 641 break; 642 643 case 1: 644 case 2: 645 case 3: 646 type = APPEND_FRAME; // APPEND or FULL 647 break; 648 } 649 } else if (localsSize == clocalsSize && cstackSize == 1) { 650 // SAME_LOCAL_1_STACK or FULL 651 type = delta < 63 652 ? SAME_LOCALS_1_STACK_ITEM_FRAME 653 : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED; 654 } 655 656 if (type != FULL_FRAME) { 657 // verify if stack and locals are the same 658 for (int j = 0; j < localsSize && type != FULL_FRAME; j++) { 659 if (!locals.get(j).equals(clocals.get(j))) 660 type = FULL_FRAME; 661 } 662 } 663 664 switch (type) { 665 case SAME_FRAME: 666 bv.putByte(delta); 667 break; 668 669 case SAME_LOCALS_1_STACK_ITEM_FRAME: 670 bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); 671 writeTypeInfos(bv, cw, cstack, 0, 1); 672 break; 673 674 case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: 675 bv.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED); 676 writeSize(delta, bv, isExtCodeSize); 677 writeTypeInfos(bv, cw, cstack, 0, 1); 678 break; 679 680 case SAME_FRAME_EXTENDED: 681 bv.putByte(SAME_FRAME_EXTENDED); 682 writeSize(delta, bv, isExtCodeSize); 683 break; 684 685 case CHOP_FRAME: 686 bv.putByte(SAME_FRAME_EXTENDED + k); // negative k 687 writeSize(delta, bv, isExtCodeSize); 688 break; 689 690 case APPEND_FRAME: 691 bv.putByte(SAME_FRAME_EXTENDED + k); // positive k 692 writeSize(delta, bv, isExtCodeSize); 693 writeTypeInfos(bv, 694 cw, 695 clocals, 696 clocalsSize - 1, 697 clocalsSize); 698 break; 699 700 case FULL_FRAME: 701 bv.putByte(FULL_FRAME); 702 writeSize(delta, bv, isExtCodeSize); 703 writeSize(clocalsSize, bv, isExtLocals); 704 writeTypeInfos(bv, cw, clocals, 0, clocalsSize); 705 writeSize(cstackSize, bv, isExtStack); 706 writeTypeInfos(bv, cw, cstack, 0, cstackSize); 707 break; 708 709 default: 710 throw new RuntimeException(); 711 } 712 offset = coffset + 1; // compensating non first offset 713 locals = clocals; 714 } 715 return bv; 716 } 717 718 private void writeSize(int delta, ByteVector bv, boolean isExt) { 719 if (isExt) { 720 bv.putInt(delta); 721 } else { 722 bv.putShort(delta); 723 } 724 } 725 726 private void writeTypeInfos( 727 ByteVector bv, 728 ClassWriter cw, 729 List info, 730 int start, 731 int end) 732 { 733 for (int j = start; j < end; j++) { 734 StackMapType typeInfo = (StackMapType) info.get(j); 735 bv.putByte(typeInfo.getType()); 736 737 switch (typeInfo.getType()) { 738 case StackMapType.ITEM_Object: // 739 bv.putShort(cw.newClass(typeInfo.getObject())); 740 break; 741 742 case StackMapType.ITEM_Uninitialized: // 743 bv.putShort(typeInfo.getLabel().getOffset()); 744 break; 745 746 } 747 } 748 } 749 750 public static int getMethodOff(ClassReader cr, int codeOff, char[] buf) { 751 int off = cr.header + 6; 752 753 int interfacesCount = cr.readUnsignedShort(off); 754 off += 2 + interfacesCount * 2; 755 756 int fieldsCount = cr.readUnsignedShort(off); 757 off += 2; 758 for (; fieldsCount > 0; --fieldsCount) { 759 int attrCount = cr.readUnsignedShort(off + 6); // field attributes 760 off += 8; 761 for (; attrCount > 0; --attrCount) { 762 off += 6 + cr.readInt(off + 2); 763 } 764 } 765 766 int methodsCount = cr.readUnsignedShort(off); 767 off += 2; 768 for (; methodsCount > 0; --methodsCount) { 769 int methodOff = off; 770 int attrCount = cr.readUnsignedShort(off + 6); // method attributes 771 off += 8; 772 for (; attrCount > 0; --attrCount) { 773 String attrName = cr.readUTF8(off, buf); 774 off += 6; 775 if (attrName.equals("Code")) { 776 if (codeOff == off) { 777 return methodOff; 778 } 779 } 780 off += cr.readInt(off - 4); 781 } 782 } 783 784 return -1; 785 } 786 787 /** 788 * Use method signature and access flags to resolve initial locals state. 789 * 790 * @param className name of the method's owner class. 791 * @param access access flags of the method. 792 * @param methodName name of the method. 793 * @param methodDesc descriptor of the method. 794 * @return list of <code>StackMapType</code> instances representing locals 795 * for an initial frame. 796 */ 797 public static List calculateLocals( 798 String className, 799 int access, 800 String methodName, 801 String methodDesc) 802 { 803 List locals = new ArrayList(); 804 805 // TODO 806 if ("<init>".equals(methodName) 807 && !className.equals("java/lang/Object")) 808 { 809 StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_UninitializedThis); 810 typeInfo.setObject(className); // this 811 locals.add(typeInfo); 812 } else if ((access & Opcodes.ACC_STATIC) == 0) { 813 StackMapType typeInfo = StackMapType.getTypeInfo(StackMapType.ITEM_Object); 814 typeInfo.setObject(className); // this 815 locals.add(typeInfo); 816 } 817 818 Type[] types = Type.getArgumentTypes(methodDesc); 819 for (int i = 0; i < types.length; i++) { 820 Type t = types[i]; 821 StackMapType smt; 822 switch (t.getSort()) { 823 case Type.LONG: 824 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Long); 825 break; 826 case Type.DOUBLE: 827 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Double); 828 break; 829 830 case Type.FLOAT: 831 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Float); 832 break; 833 834 case Type.ARRAY: 835 case Type.OBJECT: 836 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Object); 837 smt.setObject(t.getDescriptor()); // TODO verify name 838 break; 839 840 default: 841 smt = StackMapType.getTypeInfo(StackMapType.ITEM_Integer); 842 break; 843 } 844 } 845 846 return locals; 847 } 848 849 private int readTypes( 850 List info, 851 boolean isExt, 852 boolean isExtCodeSize, 853 ClassReader cr, 854 int off, 855 Label[] labels, 856 char[] buf) 857 { 858 int n = 0; 859 if (isExt) { 860 n = cr.readInt(off); 861 off += 4; 862 } else { 863 n = cr.readUnsignedShort(off); 864 off += 2; 865 } 866 867 for (; n > 0; n--) { 868 off = readType(info, isExtCodeSize, cr, off, labels, buf); 869 } 870 return off; 871 } 872 873 private int readType( 874 List info, 875 boolean isExtCodeSize, 876 ClassReader cr, 877 int off, 878 Label[] labels, 879 char[] buf) 880 { 881 int itemType = cr.readByte(off++); 882 StackMapType typeInfo = StackMapType.getTypeInfo(itemType); 883 info.add(typeInfo); 884 switch (itemType) { 885 // case StackMapType.ITEM_Long: // 886 // case StackMapType.ITEM_Double: // 887 // info.add(StackMapType.getTypeInfo(StackMapType.ITEM_Top)); 888 // break; 889 890 case StackMapType.ITEM_Object: // 891 typeInfo.setObject(cr.readClass(off, buf)); 892 off += 2; 893 break; 894 895 case StackMapType.ITEM_Uninitialized: // 896 int offset; 897 if (isExtCodeSize) { 898 offset = cr.readInt(off); 899 off += 4; 900 } else { 901 offset = cr.readUnsignedShort(off); 902 off += 2; 903 } 904 905 typeInfo.setLabel(getLabel(offset, labels)); 906 break; 907 } 908 return off; 909 } 910 911 private Label getLabel(int offset, Label[] labels) { 912 Label l = labels[offset]; 913 if (l != null) { 914 return l; 915 } 916 return labels[offset] = new Label(); 917 } 918 919 public String toString() { 920 StringBuffer sb = new StringBuffer("StackMapTable["); 921 for (int i = 0; i < frames.size(); i++) { 922 sb.append('\n').append('[').append(frames.get(i)).append(']'); 923 } 924 sb.append("\n]"); 925 return sb.toString(); 926 } 927 } 928