1/* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16package javassist.bytecode; 17 18import java.util.ArrayList; 19 20/** 21 * An iterator for editing a code attribute. 22 * 23 * <p>If there are multiple <code>CodeIterator</code>s referring to the 24 * same <code>Code_attribute</code>, then inserting a gap by one 25 * <code>CodeIterator</code> will break the other 26 * <code>CodeIterator</code>. 27 * 28 * <p>This iterator does not provide <code>remove()</code>. 29 * If a piece of code in a <code>Code_attribute</code> is unnecessary, 30 * it should be overwritten with <code>NOP</code>. 31 * 32 * @see CodeAttribute#iterator() 33 */ 34public class CodeIterator implements Opcode { 35 protected CodeAttribute codeAttr; 36 protected byte[] bytecode; 37 protected int endPos; 38 protected int currentPos; 39 protected int mark; 40 41 protected CodeIterator(CodeAttribute ca) { 42 codeAttr = ca; 43 bytecode = ca.getCode(); 44 begin(); 45 } 46 47 /** 48 * Moves to the first instruction. 49 */ 50 public void begin() { 51 currentPos = mark = 0; 52 endPos = getCodeLength(); 53 } 54 55 /** 56 * Moves to the given index. 57 * 58 * <p>The index of the next instruction is set to the given index. 59 * The successive call to <code>next()</code> 60 * returns the index that has been given to <code>move()</code>. 61 * 62 * <p>Note that the index is into the byte array returned by 63 * <code>get().getCode()</code>. 64 * 65 * @see CodeAttribute#getCode() 66 */ 67 public void move(int index) { 68 currentPos = index; 69 } 70 71 /** 72 * Sets a mark to the bytecode at the given index. 73 * The mark can be used to track the position of that bytecode 74 * when code blocks are inserted. 75 * If a code block is inclusively inserted at the position of the 76 * bytecode, the mark is set to the inserted code block. 77 * 78 * @see #getMark() 79 * @since 3.11 80 */ 81 public void setMark(int index) { 82 mark = index; 83 } 84 85 /** 86 * Gets the index of the position of the mark set by 87 * <code>setMark</code>. 88 * 89 * @return the index of the position. 90 * @see #setMark(int) 91 * @since 3.11 92 */ 93 public int getMark() { return mark; } 94 95 /** 96 * Returns a Code attribute read with this iterator. 97 */ 98 public CodeAttribute get() { 99 return codeAttr; 100 } 101 102 /** 103 * Returns <code>code_length</code> of <code>Code_attribute</code>. 104 */ 105 public int getCodeLength() { 106 return bytecode.length; 107 } 108 109 /** 110 * Returns the unsigned 8bit value at the given index. 111 */ 112 public int byteAt(int index) { return bytecode[index] & 0xff; } 113 114 /** 115 * Writes an 8bit value at the given index. 116 */ 117 public void writeByte(int value, int index) { 118 bytecode[index] = (byte)value; 119 } 120 121 /** 122 * Returns the unsigned 16bit value at the given index. 123 */ 124 public int u16bitAt(int index) { 125 return ByteArray.readU16bit(bytecode, index); 126 } 127 128 /** 129 * Returns the signed 16bit value at the given index. 130 */ 131 public int s16bitAt(int index) { 132 return ByteArray.readS16bit(bytecode, index); 133 } 134 135 /** 136 * Writes a 16 bit integer at the index. 137 */ 138 public void write16bit(int value, int index) { 139 ByteArray.write16bit(value, bytecode, index); 140 } 141 142 /** 143 * Returns the signed 32bit value at the given index. 144 */ 145 public int s32bitAt(int index) { 146 return ByteArray.read32bit(bytecode, index); 147 } 148 149 /** 150 * Writes a 32bit integer at the index. 151 */ 152 public void write32bit(int value, int index) { 153 ByteArray.write32bit(value, bytecode, index); 154 } 155 156 /** 157 * Writes a byte array at the index. 158 * 159 * @param code may be a zero-length array. 160 */ 161 public void write(byte[] code, int index) { 162 int len = code.length; 163 for (int j = 0; j < len; ++j) 164 bytecode[index++] = code[j]; 165 } 166 167 /** 168 * Returns true if there is more instructions. 169 */ 170 public boolean hasNext() { return currentPos < endPos; } 171 172 /** 173 * Returns the index of the next instruction 174 * (not the operand following the current opcode). 175 * 176 * <p>Note that the index is into the byte array returned by 177 * <code>get().getCode()</code>. 178 * 179 * @see CodeAttribute#getCode() 180 * @see CodeIterator#byteAt(int) 181 */ 182 public int next() throws BadBytecode { 183 int pos = currentPos; 184 currentPos = nextOpcode(bytecode, pos); 185 return pos; 186 } 187 188 /** 189 * Obtains the value that the next call 190 * to <code>next()</code> will return. 191 * 192 * <p>This method is side-effects free. 193 * Successive calls to <code>lookAhead()</code> return the 194 * same value until <code>next()</code> is called. 195 */ 196 public int lookAhead() { 197 return currentPos; 198 } 199 200 /** 201 * Moves to the instruction for 202 * either <code>super()</code> or <code>this()</code>. 203 * 204 * <p>This method skips all the instructions for computing arguments 205 * to <code>super()</code> or <code>this()</code>, which should be 206 * placed at the beginning of a constructor body. 207 * 208 * <p>This method returns the index of INVOKESPECIAL instruction 209 * executing <code>super()</code> or <code>this()</code>. 210 * A successive call to <code>next()</code> returns the 211 * index of the next instruction following that INVOKESPECIAL. 212 * 213 * <p>This method works only for a constructor. 214 * 215 * @return the index of the INVOKESPECIAL instruction, or -1 216 * if a constructor invocation is not found. 217 */ 218 public int skipConstructor() throws BadBytecode { 219 return skipSuperConstructor0(-1); 220 } 221 222 /** 223 * Moves to the instruction for <code>super()</code>. 224 * 225 * <p>This method skips all the instructions for computing arguments to 226 * <code>super()</code>, which should be 227 * placed at the beginning of a constructor body. 228 * 229 * <p>This method returns the index of INVOKESPECIAL instruction 230 * executing <code>super()</code>. 231 * A successive call to <code>next()</code> returns the 232 * index of the next instruction following that INVOKESPECIAL. 233 * 234 * <p>This method works only for a constructor. 235 * 236 * @return the index of the INVOKESPECIAL instruction, or -1 237 * if a super constructor invocation is not found 238 * but <code>this()</code> is found. 239 */ 240 public int skipSuperConstructor() throws BadBytecode { 241 return skipSuperConstructor0(0); 242 } 243 244 /** 245 * Moves to the instruction for <code>this()</code>. 246 * 247 * <p>This method skips all the instructions for computing arguments to 248 * <code>this()</code>, which should be 249 * placed at the beginning of a constructor body. 250 * 251 * <p>This method returns the index of INVOKESPECIAL instruction 252 * executing <code>this()</code>. 253 * A successive call to <code>next()</code> returns the 254 * index of the next instruction following that INVOKESPECIAL. 255 * 256 * <p>This method works only for a constructor. 257 * 258 * @return the index of the INVOKESPECIAL instruction, or -1 259 * if a explicit constructor invocation is not found 260 * but <code>super()</code> is found. 261 */ 262 public int skipThisConstructor() throws BadBytecode { 263 return skipSuperConstructor0(1); 264 } 265 266 /* skipSuper 1: this(), 0: super(), -1: both. 267 */ 268 private int skipSuperConstructor0(int skipThis) throws BadBytecode { 269 begin(); 270 ConstPool cp = codeAttr.getConstPool(); 271 String thisClassName = codeAttr.getDeclaringClass(); 272 int nested = 0; 273 while (hasNext()) { 274 int index = next(); 275 int c = byteAt(index); 276 if (c == NEW) 277 ++nested; 278 else if (c == INVOKESPECIAL) { 279 int mref = ByteArray.readU16bit(bytecode, index + 1); 280 if (cp.getMethodrefName(mref).equals(MethodInfo.nameInit)) 281 if (--nested < 0) { 282 if (skipThis < 0) 283 return index; 284 285 String cname = cp.getMethodrefClassName(mref); 286 if (cname.equals(thisClassName) == (skipThis > 0)) 287 return index; 288 else 289 break; 290 } 291 } 292 } 293 294 begin(); 295 return -1; 296 } 297 298 /** 299 * Inserts the given bytecode sequence 300 * before the next instruction that would be returned by 301 * <code>next()</code> (not before the instruction returned 302 * by the last call to <code>next()</code>). 303 * Branch offsets and the exception table are also updated. 304 * 305 * <p>If the next instruction is at the beginning of a block statement, 306 * then the bytecode is inserted within that block. 307 * 308 * <p>An extra gap may be inserted at the end of the inserted 309 * bytecode sequence for adjusting alignment if the code attribute 310 * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. 311 * 312 * @param code inserted bytecode sequence. 313 * @return the index indicating the first byte of the 314 * inserted byte sequence. 315 */ 316 public int insert(byte[] code) 317 throws BadBytecode 318 { 319 return insert0(currentPos, code, false); 320 } 321 322 /** 323 * Inserts the given bytecode sequence 324 * before the instruction at the given index <code>pos</code>. 325 * Branch offsets and the exception table are also updated. 326 * 327 * <p>If the instruction at the given index is at the beginning 328 * of a block statement, 329 * then the bytecode is inserted within that block. 330 * 331 * <p>An extra gap may be inserted at the end of the inserted 332 * bytecode sequence for adjusting alignment if the code attribute 333 * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. 334 * 335 * <p>The index at which the byte sequence is actually inserted 336 * might be different from pos since some other bytes might be 337 * inserted at other positions (e.g. to change <code>GOTO</code> 338 * to <code>GOTO_W</code>). 339 * 340 * @param pos the index at which a byte sequence is inserted. 341 * @param code inserted bytecode sequence. 342 */ 343 public void insert(int pos, byte[] code) throws BadBytecode { 344 insert0(pos, code, false); 345 } 346 347 /** 348 * Inserts the given bytecode sequence 349 * before the instruction at the given index <code>pos</code>. 350 * Branch offsets and the exception table are also updated. 351 * 352 * <p>If the instruction at the given index is at the beginning 353 * of a block statement, 354 * then the bytecode is inserted within that block. 355 * 356 * <p>An extra gap may be inserted at the end of the inserted 357 * bytecode sequence for adjusting alignment if the code attribute 358 * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. 359 * 360 * @param pos the index at which a byte sequence is inserted. 361 * @param code inserted bytecode sequence. 362 * @return the index indicating the first byte of the 363 * inserted byte sequence, which might be 364 * different from pos. 365 * @since 3.11 366 */ 367 public int insertAt(int pos, byte[] code) throws BadBytecode { 368 return insert0(pos, code, false); 369 } 370 371 /** 372 * Inserts the given bytecode sequence exclusively 373 * before the next instruction that would be returned by 374 * <code>next()</code> (not before the instruction returned 375 * by tha last call to <code>next()</code>). 376 * Branch offsets and the exception table are also updated. 377 * 378 * <p>If the next instruction is at the beginning of a block statement, 379 * then the bytecode is excluded from that block. 380 * 381 * <p>An extra gap may be inserted at the end of the inserted 382 * bytecode sequence for adjusting alignment if the code attribute 383 * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. 384 * 385 * @param code inserted bytecode sequence. 386 * @return the index indicating the first byte of the 387 * inserted byte sequence. 388 */ 389 public int insertEx(byte[] code) 390 throws BadBytecode 391 { 392 return insert0(currentPos, code, true); 393 } 394 395 /** 396 * Inserts the given bytecode sequence exclusively 397 * before the instruction at the given index <code>pos</code>. 398 * Branch offsets and the exception table are also updated. 399 * 400 * <p>If the instruction at the given index is at the beginning 401 * of a block statement, 402 * then the bytecode is excluded from that block. 403 * 404 * <p>An extra gap may be inserted at the end of the inserted 405 * bytecode sequence for adjusting alignment if the code attribute 406 * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. 407 * 408 * <p>The index at which the byte sequence is actually inserted 409 * might be different from pos since some other bytes might be 410 * inserted at other positions (e.g. to change <code>GOTO</code> 411 * to <code>GOTO_W</code>). 412 * 413 * @param pos the index at which a byte sequence is inserted. 414 * @param code inserted bytecode sequence. 415 */ 416 public void insertEx(int pos, byte[] code) throws BadBytecode { 417 insert0(pos, code, true); 418 } 419 420 /** 421 * Inserts the given bytecode sequence exclusively 422 * before the instruction at the given index <code>pos</code>. 423 * Branch offsets and the exception table are also updated. 424 * 425 * <p>If the instruction at the given index is at the beginning 426 * of a block statement, 427 * then the bytecode is excluded from that block. 428 * 429 * <p>An extra gap may be inserted at the end of the inserted 430 * bytecode sequence for adjusting alignment if the code attribute 431 * includes <code>LOOKUPSWITCH</code> or <code>TABLESWITCH</code>. 432 * 433 * @param pos the index at which a byte sequence is inserted. 434 * @param code inserted bytecode sequence. 435 * @return the index indicating the first byte of the 436 * inserted byte sequence, which might be 437 * different from pos. 438 * @since 3.11 439 */ 440 public int insertExAt(int pos, byte[] code) throws BadBytecode { 441 return insert0(pos, code, true); 442 } 443 444 /** 445 * @return the index indicating the first byte of the 446 * inserted byte sequence. 447 */ 448 private int insert0(int pos, byte[] code, boolean exclusive) 449 throws BadBytecode 450 { 451 int len = code.length; 452 if (len <= 0) 453 return pos; 454 455 // currentPos will change. 456 pos = insertGapAt(pos, len, exclusive).position; 457 458 int p = pos; 459 for (int j = 0; j < len; ++j) 460 bytecode[p++] = code[j]; 461 462 return pos; 463 } 464 465 /** 466 * Inserts a gap 467 * before the next instruction that would be returned by 468 * <code>next()</code> (not before the instruction returned 469 * by the last call to <code>next()</code>). 470 * Branch offsets and the exception table are also updated. 471 * The inserted gap is filled with NOP. The gap length may be 472 * extended to a multiple of 4. 473 * 474 * <p>If the next instruction is at the beginning of a block statement, 475 * then the gap is inserted within that block. 476 * 477 * @param length gap length 478 * @return the index indicating the first byte of the inserted gap. 479 */ 480 public int insertGap(int length) throws BadBytecode { 481 return insertGapAt(currentPos, length, false).position; 482 } 483 484 /** 485 * Inserts a gap in front of the instruction at the given 486 * index <code>pos</code>. 487 * Branch offsets and the exception table are also updated. 488 * The inserted gap is filled with NOP. The gap length may be 489 * extended to a multiple of 4. 490 * 491 * <p>If the instruction at the given index is at the beginning 492 * of a block statement, 493 * then the gap is inserted within that block. 494 * 495 * @param pos the index at which a gap is inserted. 496 * @param length gap length. 497 * @return the length of the inserted gap. 498 * It might be bigger than <code>length</code>. 499 */ 500 public int insertGap(int pos, int length) throws BadBytecode { 501 return insertGapAt(pos, length, false).length; 502 } 503 504 /** 505 * Inserts an exclusive gap 506 * before the next instruction that would be returned by 507 * <code>next()</code> (not before the instruction returned 508 * by the last call to <code>next()</code>). 509 * Branch offsets and the exception table are also updated. 510 * The inserted gap is filled with NOP. The gap length may be 511 * extended to a multiple of 4. 512 * 513 * <p>If the next instruction is at the beginning of a block statement, 514 * then the gap is excluded from that block. 515 * 516 * @param length gap length 517 * @return the index indicating the first byte of the inserted gap. 518 */ 519 public int insertExGap(int length) throws BadBytecode { 520 return insertGapAt(currentPos, length, true).position; 521 } 522 523 /** 524 * Inserts an exclusive gap in front of the instruction at the given 525 * index <code>pos</code>. 526 * Branch offsets and the exception table are also updated. 527 * The inserted gap is filled with NOP. The gap length may be 528 * extended to a multiple of 4. 529 * 530 * <p>If the instruction at the given index is at the beginning 531 * of a block statement, 532 * then the gap is excluded from that block. 533 * 534 * @param pos the index at which a gap is inserted. 535 * @param length gap length. 536 * @return the length of the inserted gap. 537 * It might be bigger than <code>length</code>. 538 */ 539 public int insertExGap(int pos, int length) throws BadBytecode { 540 return insertGapAt(pos, length, true).length; 541 } 542 543 /** 544 * An inserted gap. 545 * 546 * @since 3.11 547 */ 548 public static class Gap { 549 /** 550 * The position of the gap. 551 */ 552 public int position; 553 554 /** 555 * The length of the gap. 556 */ 557 public int length; 558 } 559 560 /** 561 * Inserts an inclusive or exclusive gap in front of the instruction 562 * at the given index <code>pos</code>. 563 * Branch offsets and the exception table in the method body 564 * are also updated. The inserted gap is filled with NOP. 565 * The gap length may be extended to a multiple of 4. 566 * 567 * <p>Suppose that the instruction at the given index is at the 568 * beginning of a block statement. If the gap is inclusive, 569 * then it is included within that block. If the gap is exclusive, 570 * then it is excluded from that block. 571 * 572 * <p>The index at which the gap is actually inserted 573 * might be different from pos since some other bytes might be 574 * inserted at other positions (e.g. to change <code>GOTO</code> 575 * to <code>GOTO_W</code>). The index is available from the <code>Gap</code> 576 * object returned by this method. 577 * 578 * <p>Suppose that the gap is inserted at the position of 579 * the next instruction that would be returned by 580 * <code>next()</code> (not the last instruction returned 581 * by the last call to <code>next()</code>). The next 582 * instruction returned by <code>next()</code> after the gap is 583 * inserted is still the same instruction. It is not <code>NOP</code> 584 * at the first byte of the inserted gap. 585 * 586 * @param pos the index at which a gap is inserted. 587 * @param length gap length. 588 * @param exclusive true if exclusive, otherwise false. 589 * @return the position and the length of the inserted gap. 590 * @since 3.11 591 */ 592 public Gap insertGapAt(int pos, int length, boolean exclusive) 593 throws BadBytecode 594 { 595 /** 596 * cursorPos indicates the next bytecode whichever exclusive is 597 * true or false. 598 */ 599 Gap gap = new Gap(); 600 if (length <= 0) { 601 gap.position = pos; 602 gap.length = 0; 603 return gap; 604 } 605 606 byte[] c; 607 int length2; 608 if (bytecode.length + length > Short.MAX_VALUE) { 609 // currentPos might change after calling insertGapCore0w(). 610 c = insertGapCore0w(bytecode, pos, length, exclusive, 611 get().getExceptionTable(), codeAttr, gap); 612 pos = gap.position; 613 length2 = length; // == gap.length 614 } 615 else { 616 int cur = currentPos; 617 c = insertGapCore0(bytecode, pos, length, exclusive, 618 get().getExceptionTable(), codeAttr); 619 // insertGapCore0() never changes pos. 620 length2 = c.length - bytecode.length; 621 gap.position = pos; 622 gap.length = length2; 623 if (cur >= pos) 624 currentPos = cur + length2; 625 626 if (mark > pos || (mark == pos && exclusive)) 627 mark += length2; 628 } 629 630 codeAttr.setCode(c); 631 bytecode = c; 632 endPos = getCodeLength(); 633 updateCursors(pos, length2); 634 return gap; 635 } 636 637 /** 638 * Is called when a gap is inserted. The default implementation is empty. 639 * A subclass can override this method so that cursors will be updated. 640 * 641 * @param pos the position where a gap is inserted. 642 * @param length the length of the gap. 643 */ 644 protected void updateCursors(int pos, int length) { 645 // empty 646 } 647 648 /** 649 * Copies and inserts the entries in the given exception table 650 * at the beginning of the exception table in the code attribute 651 * edited by this object. 652 * 653 * @param offset the value added to the code positions included 654 * in the entries. 655 */ 656 public void insert(ExceptionTable et, int offset) { 657 codeAttr.getExceptionTable().add(0, et, offset); 658 } 659 660 /** 661 * Appends the given bytecode sequence at the end. 662 * 663 * @param code the bytecode appended. 664 * @return the position of the first byte of the appended bytecode. 665 */ 666 public int append(byte[] code) { 667 int size = getCodeLength(); 668 int len = code.length; 669 if (len <= 0) 670 return size; 671 672 appendGap(len); 673 byte[] dest = bytecode; 674 for (int i = 0; i < len; ++i) 675 dest[i + size] = code[i]; 676 677 return size; 678 } 679 680 /** 681 * Appends a gap at the end of the bytecode sequence. 682 * 683 * @param gapLength gap length 684 */ 685 public void appendGap(int gapLength) { 686 byte[] code = bytecode; 687 int codeLength = code.length; 688 byte[] newcode = new byte[codeLength + gapLength]; 689 690 int i; 691 for (i = 0; i < codeLength; ++i) 692 newcode[i] = code[i]; 693 694 for (i = codeLength; i < codeLength + gapLength; ++i) 695 newcode[i] = NOP; 696 697 codeAttr.setCode(newcode); 698 bytecode = newcode; 699 endPos = getCodeLength(); 700 } 701 702 /** 703 * Copies and appends the entries in the given exception table 704 * at the end of the exception table in the code attribute 705 * edited by this object. 706 * 707 * @param offset the value added to the code positions included 708 * in the entries. 709 */ 710 public void append(ExceptionTable et, int offset) { 711 ExceptionTable table = codeAttr.getExceptionTable(); 712 table.add(table.size(), et, offset); 713 } 714 715 /* opcodeLegth is used for implementing nextOpcode(). 716 */ 717 private static final int opcodeLength[] = { 718 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 3, 719 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 721 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 722 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 723 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 724 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 725 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 726 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 0, 1, 1, 1, 1, 1, 1, 3, 3, 727 3, 3, 3, 3, 3, 5, 0, 3, 2, 3, 1, 1, 3, 3, 1, 1, 0, 4, 3, 3, 728 5, 5 729 }; 730 // 0 .. UNUSED (186), LOOKUPSWITCH, TABLESWITCH, WIDE 731 732 /** 733 * Calculates the index of the next opcode. 734 */ 735 static int nextOpcode(byte[] code, int index) 736 throws BadBytecode 737 { 738 int opcode; 739 try { 740 opcode = code[index] & 0xff; 741 } 742 catch (IndexOutOfBoundsException e) { 743 throw new BadBytecode("invalid opcode address"); 744 } 745 746 try { 747 int len = opcodeLength[opcode]; 748 if (len > 0) 749 return index + len; 750 else if (opcode == WIDE) 751 if (code[index + 1] == (byte)IINC) // WIDE IINC 752 return index + 6; 753 else 754 return index + 4; // WIDE ... 755 else { 756 int index2 = (index & ~3) + 8; 757 if (opcode == LOOKUPSWITCH) { 758 int npairs = ByteArray.read32bit(code, index2); 759 return index2 + npairs * 8 + 4; 760 } 761 else if (opcode == TABLESWITCH) { 762 int low = ByteArray.read32bit(code, index2); 763 int high = ByteArray.read32bit(code, index2 + 4); 764 return index2 + (high - low + 1) * 4 + 8; 765 } 766 // else 767 // throw new BadBytecode(opcode); 768 } 769 } 770 catch (IndexOutOfBoundsException e) { 771 } 772 773 // opcode is UNUSED or an IndexOutOfBoundsException was thrown. 774 throw new BadBytecode(opcode); 775 } 776 777 // methods for implementing insertGap(). 778 779 static class AlignmentException extends Exception {} 780 781 /** 782 * insertGapCore0() inserts a gap (some NOPs). 783 * It cannot handle a long code sequence more than 32K. All branch offsets must be 784 * signed 16bits. 785 * 786 * If "where" is the beginning of a block statement and exclusive is false, 787 * then the inserted gap is also included in the block statement. 788 * "where" must indicate the first byte of an opcode. 789 * The inserted gap is filled with NOP. gapLength may be extended to 790 * a multiple of 4. 791 * 792 * This method was also called from CodeAttribute.LdcEntry.doit(). 793 * 794 * @param where It must indicate the first byte of an opcode. 795 */ 796 static byte[] insertGapCore0(byte[] code, int where, int gapLength, 797 boolean exclusive, ExceptionTable etable, CodeAttribute ca) 798 throws BadBytecode 799 { 800 if (gapLength <= 0) 801 return code; 802 803 try { 804 return insertGapCore1(code, where, gapLength, exclusive, etable, ca); 805 } 806 catch (AlignmentException e) { 807 try { 808 return insertGapCore1(code, where, (gapLength + 3) & ~3, 809 exclusive, etable, ca); 810 } 811 catch (AlignmentException e2) { 812 throw new RuntimeException("fatal error?"); 813 } 814 } 815 } 816 817 private static byte[] insertGapCore1(byte[] code, int where, int gapLength, 818 boolean exclusive, ExceptionTable etable, 819 CodeAttribute ca) 820 throws BadBytecode, AlignmentException 821 { 822 int codeLength = code.length; 823 byte[] newcode = new byte[codeLength + gapLength]; 824 insertGap2(code, where, gapLength, codeLength, newcode, exclusive); 825 etable.shiftPc(where, gapLength, exclusive); 826 LineNumberAttribute na 827 = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); 828 if (na != null) 829 na.shiftPc(where, gapLength, exclusive); 830 831 LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute( 832 LocalVariableAttribute.tag); 833 if (va != null) 834 va.shiftPc(where, gapLength, exclusive); 835 836 LocalVariableAttribute vta 837 = (LocalVariableAttribute)ca.getAttribute( 838 LocalVariableAttribute.typeTag); 839 if (vta != null) 840 vta.shiftPc(where, gapLength, exclusive); 841 842 StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag); 843 if (smt != null) 844 smt.shiftPc(where, gapLength, exclusive); 845 846 StackMap sm = (StackMap)ca.getAttribute(StackMap.tag); 847 if (sm != null) 848 sm.shiftPc(where, gapLength, exclusive); 849 850 return newcode; 851 } 852 853 private static void insertGap2(byte[] code, int where, int gapLength, 854 int endPos, byte[] newcode, boolean exclusive) 855 throws BadBytecode, AlignmentException 856 { 857 int nextPos; 858 int i = 0; 859 int j = 0; 860 for (; i < endPos; i = nextPos) { 861 if (i == where) { 862 int j2 = j + gapLength; 863 while (j < j2) 864 newcode[j++] = NOP; 865 } 866 867 nextPos = nextOpcode(code, i); 868 int inst = code[i] & 0xff; 869 // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr 870 if ((153 <= inst && inst <= 168) 871 || inst == IFNULL || inst == IFNONNULL) { 872 /* 2bytes *signed* offset */ 873 int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff); 874 offset = newOffset(i, offset, where, gapLength, exclusive); 875 newcode[j] = code[i]; 876 ByteArray.write16bit(offset, newcode, j + 1); 877 j += 3; 878 } 879 else if (inst == GOTO_W || inst == JSR_W) { 880 /* 4bytes offset */ 881 int offset = ByteArray.read32bit(code, i + 1); 882 offset = newOffset(i, offset, where, gapLength, exclusive); 883 newcode[j++] = code[i]; 884 ByteArray.write32bit(offset, newcode, j); 885 j += 4; 886 } 887 else if (inst == TABLESWITCH) { 888 if (i != j && (gapLength & 3) != 0) 889 throw new AlignmentException(); 890 891 int i2 = (i & ~3) + 4; // 0-3 byte padding 892 // IBM JVM 1.4.2 cannot run the following code: 893 // int i0 = i; 894 // while (i0 < i2) 895 // newcode[j++] = code[i0++]; 896 // So extracting this code into an external method. 897 // see JIRA JASSIST-74. 898 j = copyGapBytes(newcode, j, code, i, i2); 899 900 int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2), 901 where, gapLength, exclusive); 902 ByteArray.write32bit(defaultbyte, newcode, j); 903 int lowbyte = ByteArray.read32bit(code, i2 + 4); 904 ByteArray.write32bit(lowbyte, newcode, j + 4); 905 int highbyte = ByteArray.read32bit(code, i2 + 8); 906 ByteArray.write32bit(highbyte, newcode, j + 8); 907 j += 12; 908 int i0 = i2 + 12; 909 i2 = i0 + (highbyte - lowbyte + 1) * 4; 910 while (i0 < i2) { 911 int offset = newOffset(i, ByteArray.read32bit(code, i0), 912 where, gapLength, exclusive); 913 ByteArray.write32bit(offset, newcode, j); 914 j += 4; 915 i0 += 4; 916 } 917 } 918 else if (inst == LOOKUPSWITCH) { 919 if (i != j && (gapLength & 3) != 0) 920 throw new AlignmentException(); 921 922 int i2 = (i & ~3) + 4; // 0-3 byte padding 923 924 // IBM JVM 1.4.2 cannot run the following code: 925 // int i0 = i; 926 // while (i0 < i2) 927 // newcode[j++] = code[i0++]; 928 // So extracting this code into an external method. 929 // see JIRA JASSIST-74. 930 j = copyGapBytes(newcode, j, code, i, i2); 931 932 int defaultbyte = newOffset(i, ByteArray.read32bit(code, i2), 933 where, gapLength, exclusive); 934 ByteArray.write32bit(defaultbyte, newcode, j); 935 int npairs = ByteArray.read32bit(code, i2 + 4); 936 ByteArray.write32bit(npairs, newcode, j + 4); 937 j += 8; 938 int i0 = i2 + 8; 939 i2 = i0 + npairs * 8; 940 while (i0 < i2) { 941 ByteArray.copy32bit(code, i0, newcode, j); 942 int offset = newOffset(i, 943 ByteArray.read32bit(code, i0 + 4), 944 where, gapLength, exclusive); 945 ByteArray.write32bit(offset, newcode, j + 4); 946 j += 8; 947 i0 += 8; 948 } 949 } 950 else 951 while (i < nextPos) 952 newcode[j++] = code[i++]; 953 } 954 } 955 956 957 private static int copyGapBytes(byte[] newcode, int j, byte[] code, int i, int iEnd) { 958 switch (iEnd - i) { 959 case 4: 960 newcode[j++] = code[i++]; 961 case 3: 962 newcode[j++] = code[i++]; 963 case 2: 964 newcode[j++] = code[i++]; 965 case 1: 966 newcode[j++] = code[i++]; 967 default: 968 } 969 970 return j; 971 } 972 973 private static int newOffset(int i, int offset, int where, 974 int gapLength, boolean exclusive) { 975 int target = i + offset; 976 if (i < where) { 977 if (where < target || (exclusive && where == target)) 978 offset += gapLength; 979 } 980 else if (i == where) { 981 // This code is different from the code in Branch#shiftOffset(). 982 // see JASSIST-124. 983 if (target < where) 984 offset -= gapLength; 985 } 986 else 987 if (target < where || (!exclusive && where == target)) 988 offset -= gapLength; 989 990 return offset; 991 } 992 993 static class Pointers { 994 int cursor; 995 int mark0, mark; 996 ExceptionTable etable; 997 LineNumberAttribute line; 998 LocalVariableAttribute vars, types; 999 StackMapTable stack; 1000 StackMap stack2; 1001 1002 Pointers(int cur, int m, int m0, ExceptionTable et, CodeAttribute ca) { 1003 cursor = cur; 1004 mark = m; 1005 mark0 = m0; 1006 etable = et; // non null 1007 line = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag); 1008 vars = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.tag); 1009 types = (LocalVariableAttribute)ca.getAttribute(LocalVariableAttribute.typeTag); 1010 stack = (StackMapTable)ca.getAttribute(StackMapTable.tag); 1011 stack2 = (StackMap)ca.getAttribute(StackMap.tag); 1012 } 1013 1014 void shiftPc(int where, int gapLength, boolean exclusive) throws BadBytecode { 1015 if (where < cursor || (where == cursor && exclusive)) 1016 cursor += gapLength; 1017 1018 if (where < mark || (where == mark && exclusive)) 1019 mark += gapLength; 1020 1021 if (where < mark0 || (where == mark0 && exclusive)) 1022 mark0 += gapLength; 1023 1024 etable.shiftPc(where, gapLength, exclusive); 1025 if (line != null) 1026 line.shiftPc(where, gapLength, exclusive); 1027 1028 if (vars != null) 1029 vars.shiftPc(where, gapLength, exclusive); 1030 1031 if (types != null) 1032 types.shiftPc(where, gapLength, exclusive); 1033 1034 if (stack != null) 1035 stack.shiftPc(where, gapLength, exclusive); 1036 1037 if (stack2 != null) 1038 stack2.shiftPc(where, gapLength, exclusive); 1039 } 1040 } 1041 1042 /* 1043 * This method is called from CodeAttribute.LdcEntry.doit(). 1044 */ 1045 static byte[] changeLdcToLdcW(byte[] code, ExceptionTable etable, 1046 CodeAttribute ca, CodeAttribute.LdcEntry ldcs) 1047 throws BadBytecode 1048 { 1049 ArrayList jumps = makeJumpList(code, code.length); 1050 while (ldcs != null) { 1051 addLdcW(ldcs, jumps); 1052 ldcs = ldcs.next; 1053 } 1054 1055 Pointers pointers = new Pointers(0, 0, 0, etable, ca); 1056 byte[] r = insertGap2w(code, 0, 0, false, jumps, pointers); 1057 return r; 1058 } 1059 1060 private static void addLdcW(CodeAttribute.LdcEntry ldcs, ArrayList jumps) { 1061 int where = ldcs.where; 1062 LdcW ldcw = new LdcW(where, ldcs.index); 1063 int s = jumps.size(); 1064 for (int i = 0; i < s; i++) 1065 if (where < ((Branch)jumps.get(i)).orgPos) { 1066 jumps.add(i, ldcw); 1067 return; 1068 } 1069 1070 jumps.add(ldcw); 1071 } 1072 1073 /* 1074 * insertGapCore0w() can handle a long code sequence more than 32K. 1075 * It guarantees that the length of the inserted gap (NOPs) is equal to 1076 * gapLength. No other NOPs except some NOPs following TABLESWITCH or 1077 * LOOKUPSWITCH will not be inserted. 1078 * 1079 * Note: currentPos might be moved. 1080 * 1081 * @param where It must indicate the first byte of an opcode. 1082 * @param newWhere It contains the updated index of the position where a gap 1083 * is inserted and the length of the gap. 1084 * It must not be null. 1085 */ 1086 private byte[] insertGapCore0w(byte[] code, int where, int gapLength, boolean exclusive, 1087 ExceptionTable etable, CodeAttribute ca, Gap newWhere) 1088 throws BadBytecode 1089 { 1090 if (gapLength <= 0) 1091 return code; 1092 1093 ArrayList jumps = makeJumpList(code, code.length); 1094 Pointers pointers = new Pointers(currentPos, mark, where, etable, ca); 1095 byte[] r = insertGap2w(code, where, gapLength, exclusive, jumps, pointers); 1096 currentPos = pointers.cursor; 1097 mark = pointers.mark; 1098 int where2 = pointers.mark0; 1099 if (where2 == currentPos && !exclusive) 1100 currentPos += gapLength; 1101 1102 if (exclusive) 1103 where2 -= gapLength; 1104 1105 newWhere.position = where2; 1106 newWhere.length = gapLength; 1107 return r; 1108 } 1109 1110 private static byte[] insertGap2w(byte[] code, int where, int gapLength, 1111 boolean exclusive, ArrayList jumps, Pointers ptrs) 1112 throws BadBytecode 1113 { 1114 int n = jumps.size(); 1115 if (gapLength > 0) { 1116 ptrs.shiftPc(where, gapLength, exclusive); 1117 for (int i = 0; i < n; i++) 1118 ((Branch)jumps.get(i)).shift(where, gapLength, exclusive); 1119 } 1120 1121 boolean unstable = true; 1122 do { 1123 while (unstable) { 1124 unstable = false; 1125 for (int i = 0; i < n; i++) { 1126 Branch b = (Branch)jumps.get(i); 1127 if (b.expanded()) { 1128 unstable = true; 1129 int p = b.pos; 1130 int delta = b.deltaSize(); 1131 ptrs.shiftPc(p, delta, false); 1132 for (int j = 0; j < n; j++) 1133 ((Branch)jumps.get(j)).shift(p, delta, false); 1134 } 1135 } 1136 } 1137 1138 for (int i = 0; i < n; i++) { 1139 Branch b = (Branch)jumps.get(i); 1140 int diff = b.gapChanged(); 1141 if (diff > 0) { 1142 unstable = true; 1143 int p = b.pos; 1144 ptrs.shiftPc(p, diff, false); 1145 for (int j = 0; j < n; j++) 1146 ((Branch)jumps.get(j)).shift(p, diff, false); 1147 } 1148 } 1149 } while (unstable); 1150 1151 return makeExapndedCode(code, jumps, where, gapLength); 1152 } 1153 1154 private static ArrayList makeJumpList(byte[] code, int endPos) 1155 throws BadBytecode 1156 { 1157 ArrayList jumps = new ArrayList(); 1158 int nextPos; 1159 for (int i = 0; i < endPos; i = nextPos) { 1160 nextPos = nextOpcode(code, i); 1161 int inst = code[i] & 0xff; 1162 // if<cond>, if_icmp<cond>, if_acmp<cond>, goto, jsr 1163 if ((153 <= inst && inst <= 168) 1164 || inst == IFNULL || inst == IFNONNULL) { 1165 /* 2bytes *signed* offset */ 1166 int offset = (code[i + 1] << 8) | (code[i + 2] & 0xff); 1167 Branch b; 1168 if (inst == GOTO || inst == JSR) 1169 b = new Jump16(i, offset); 1170 else 1171 b = new If16(i, offset); 1172 1173 jumps.add(b); 1174 } 1175 else if (inst == GOTO_W || inst == JSR_W) { 1176 /* 4bytes offset */ 1177 int offset = ByteArray.read32bit(code, i + 1); 1178 jumps.add(new Jump32(i, offset)); 1179 } 1180 else if (inst == TABLESWITCH) { 1181 int i2 = (i & ~3) + 4; // 0-3 byte padding 1182 int defaultbyte = ByteArray.read32bit(code, i2); 1183 int lowbyte = ByteArray.read32bit(code, i2 + 4); 1184 int highbyte = ByteArray.read32bit(code, i2 + 8); 1185 int i0 = i2 + 12; 1186 int size = highbyte - lowbyte + 1; 1187 int[] offsets = new int[size]; 1188 for (int j = 0; j < size; j++) { 1189 offsets[j] = ByteArray.read32bit(code, i0); 1190 i0 += 4; 1191 } 1192 1193 jumps.add(new Table(i, defaultbyte, lowbyte, highbyte, offsets)); 1194 } 1195 else if (inst == LOOKUPSWITCH) { 1196 int i2 = (i & ~3) + 4; // 0-3 byte padding 1197 int defaultbyte = ByteArray.read32bit(code, i2); 1198 int npairs = ByteArray.read32bit(code, i2 + 4); 1199 int i0 = i2 + 8; 1200 int[] matches = new int[npairs]; 1201 int[] offsets = new int[npairs]; 1202 for (int j = 0; j < npairs; j++) { 1203 matches[j] = ByteArray.read32bit(code, i0); 1204 offsets[j] = ByteArray.read32bit(code, i0 + 4); 1205 i0 += 8; 1206 } 1207 1208 jumps.add(new Lookup(i, defaultbyte, matches, offsets)); 1209 } 1210 } 1211 1212 return jumps; 1213 } 1214 1215 private static byte[] makeExapndedCode(byte[] code, ArrayList jumps, 1216 int where, int gapLength) 1217 throws BadBytecode 1218 { 1219 int n = jumps.size(); 1220 int size = code.length + gapLength; 1221 for (int i = 0; i < n; i++) { 1222 Branch b = (Branch)jumps.get(i); 1223 size += b.deltaSize(); 1224 } 1225 1226 byte[] newcode = new byte[size]; 1227 int src = 0, dest = 0, bindex = 0; 1228 int len = code.length; 1229 Branch b; 1230 int bpos; 1231 if (0 < n) { 1232 b = (Branch)jumps.get(0); 1233 bpos = b.orgPos; 1234 } 1235 else { 1236 b = null; 1237 bpos = len; // src will be never equal to bpos 1238 } 1239 1240 while (src < len) { 1241 if (src == where) { 1242 int pos2 = dest + gapLength; 1243 while (dest < pos2) 1244 newcode[dest++] = NOP; 1245 } 1246 1247 if (src != bpos) 1248 newcode[dest++] = code[src++]; 1249 else { 1250 int s = b.write(src, code, dest, newcode); 1251 src += s; 1252 dest += s + b.deltaSize(); 1253 if (++bindex < n) { 1254 b = (Branch)jumps.get(bindex); 1255 bpos = b.orgPos; 1256 } 1257 else { 1258 b = null; 1259 bpos = len; 1260 } 1261 } 1262 } 1263 1264 return newcode; 1265 } 1266 1267 static abstract class Branch { 1268 int pos, orgPos; 1269 Branch(int p) { pos = orgPos = p; } 1270 void shift(int where, int gapLength, boolean exclusive) { 1271 if (where < pos || (where == pos && exclusive)) 1272 pos += gapLength; 1273 } 1274 1275 static int shiftOffset(int i, int offset, int where, 1276 int gapLength, boolean exclusive) { 1277 int target = i + offset; 1278 if (i < where) { 1279 if (where < target || (exclusive && where == target)) 1280 offset += gapLength; 1281 } 1282 else if (i == where) { 1283 // This code is different from the code in CodeIterator#newOffset(). 1284 // see JASSIST-124. 1285 if (target < where && exclusive) 1286 offset -= gapLength; 1287 else if (where < target && !exclusive) 1288 offset += gapLength; 1289 } 1290 else 1291 if (target < where || (!exclusive && where == target)) 1292 offset -= gapLength; 1293 1294 return offset; 1295 } 1296 1297 boolean expanded() { return false; } 1298 int gapChanged() { return 0; } 1299 int deltaSize() { return 0; } // newSize - oldSize 1300 1301 // This returns the original instruction size. 1302 abstract int write(int srcPos, byte[] code, int destPos, byte[] newcode); 1303 } 1304 1305 /* used by changeLdcToLdcW() and CodeAttribute.LdcEntry. 1306 */ 1307 static class LdcW extends Branch { 1308 int index; 1309 boolean state; 1310 LdcW(int p, int i) { 1311 super(p); 1312 index = i; 1313 state = true; 1314 } 1315 1316 boolean expanded() { 1317 if (state) { 1318 state = false; 1319 return true; 1320 } 1321 else 1322 return false; 1323 } 1324 1325 int deltaSize() { return 1; } 1326 1327 int write(int srcPos, byte[] code, int destPos, byte[] newcode) { 1328 newcode[destPos] = LDC_W; 1329 ByteArray.write16bit(index, newcode, destPos + 1); 1330 return 2; 1331 } 1332 } 1333 1334 static abstract class Branch16 extends Branch { 1335 int offset; 1336 int state; 1337 static final int BIT16 = 0; 1338 static final int EXPAND = 1; 1339 static final int BIT32 = 2; 1340 1341 Branch16(int p, int off) { 1342 super(p); 1343 offset = off; 1344 state = BIT16; 1345 } 1346 1347 void shift(int where, int gapLength, boolean exclusive) { 1348 offset = shiftOffset(pos, offset, where, gapLength, exclusive); 1349 super.shift(where, gapLength, exclusive); 1350 if (state == BIT16) 1351 if (offset < Short.MIN_VALUE || Short.MAX_VALUE < offset) 1352 state = EXPAND; 1353 } 1354 1355 boolean expanded() { 1356 if (state == EXPAND) { 1357 state = BIT32; 1358 return true; 1359 } 1360 else 1361 return false; 1362 } 1363 1364 abstract int deltaSize(); 1365 abstract void write32(int src, byte[] code, int dest, byte[] newcode); 1366 1367 int write(int src, byte[] code, int dest, byte[] newcode) { 1368 if (state == BIT32) 1369 write32(src, code, dest, newcode); 1370 else { 1371 newcode[dest] = code[src]; 1372 ByteArray.write16bit(offset, newcode, dest + 1); 1373 } 1374 1375 return 3; 1376 } 1377 } 1378 1379 // GOTO or JSR 1380 static class Jump16 extends Branch16 { 1381 Jump16(int p, int off) { 1382 super(p, off); 1383 } 1384 1385 int deltaSize() { 1386 return state == BIT32 ? 2 : 0; 1387 } 1388 1389 void write32(int src, byte[] code, int dest, byte[] newcode) { 1390 newcode[dest] = (byte)(((code[src] & 0xff) == GOTO) ? GOTO_W : JSR_W); 1391 ByteArray.write32bit(offset, newcode, dest + 1); 1392 } 1393 } 1394 1395 // if<cond>, if_icmp<cond>, or if_acmp<cond> 1396 static class If16 extends Branch16 { 1397 If16(int p, int off) { 1398 super(p, off); 1399 } 1400 1401 int deltaSize() { 1402 return state == BIT32 ? 5 : 0; 1403 } 1404 1405 void write32(int src, byte[] code, int dest, byte[] newcode) { 1406 newcode[dest] = (byte)opcode(code[src] & 0xff); 1407 newcode[dest + 1] = 0; 1408 newcode[dest + 2] = 8; // branch_offset = 8 1409 newcode[dest + 3] = (byte)GOTO_W; 1410 ByteArray.write32bit(offset - 3, newcode, dest + 4); 1411 } 1412 1413 int opcode(int op) { 1414 if (op == IFNULL) 1415 return IFNONNULL; 1416 else if (op == IFNONNULL) 1417 return IFNULL; 1418 else { 1419 if (((op - IFEQ) & 1) == 0) 1420 return op + 1; 1421 else 1422 return op - 1; 1423 } 1424 } 1425 } 1426 1427 static class Jump32 extends Branch { 1428 int offset; 1429 1430 Jump32(int p, int off) { 1431 super(p); 1432 offset = off; 1433 } 1434 1435 void shift(int where, int gapLength, boolean exclusive) { 1436 offset = shiftOffset(pos, offset, where, gapLength, exclusive); 1437 super.shift(where, gapLength, exclusive); 1438 } 1439 1440 int write(int src, byte[] code, int dest, byte[] newcode) { 1441 newcode[dest] = code[src]; 1442 ByteArray.write32bit(offset, newcode, dest + 1); 1443 return 5; 1444 } 1445 } 1446 1447 static abstract class Switcher extends Branch { 1448 int gap, defaultByte; 1449 int[] offsets; 1450 1451 Switcher(int pos, int defaultByte, int[] offsets) { 1452 super(pos); 1453 this.gap = 3 - (pos & 3); 1454 this.defaultByte = defaultByte; 1455 this.offsets = offsets; 1456 } 1457 1458 void shift(int where, int gapLength, boolean exclusive) { 1459 int p = pos; 1460 defaultByte = shiftOffset(p, defaultByte, where, gapLength, exclusive); 1461 int num = offsets.length; 1462 for (int i = 0; i < num; i++) 1463 offsets[i] = shiftOffset(p, offsets[i], where, gapLength, exclusive); 1464 1465 super.shift(where, gapLength, exclusive); 1466 } 1467 1468 int gapChanged() { 1469 int newGap = 3 - (pos & 3); 1470 if (newGap > gap) { 1471 int diff = newGap - gap; 1472 gap = newGap; 1473 return diff; 1474 } 1475 1476 return 0; 1477 } 1478 1479 int deltaSize() { 1480 return gap - (3 - (orgPos & 3)); 1481 } 1482 1483 int write(int src, byte[] code, int dest, byte[] newcode) { 1484 int padding = 3 - (pos & 3); 1485 int nops = gap - padding; 1486 int bytecodeSize = 5 + (3 - (orgPos & 3)) + tableSize(); 1487 adjustOffsets(bytecodeSize, nops); 1488 newcode[dest++] = code[src]; 1489 while (padding-- > 0) 1490 newcode[dest++] = 0; 1491 1492 ByteArray.write32bit(defaultByte, newcode, dest); 1493 int size = write2(dest + 4, newcode); 1494 dest += size + 4; 1495 while (nops-- > 0) 1496 newcode[dest++] = NOP; 1497 1498 return 5 + (3 - (orgPos & 3)) + size; 1499 } 1500 1501 abstract int write2(int dest, byte[] newcode); 1502 abstract int tableSize(); 1503 1504 /* If the new bytecode size is shorter than the original, some NOPs 1505 * are appended after this branch instruction (tableswitch or 1506 * lookupswitch) to fill the gap. 1507 * This method changes a branch offset to point to the first NOP 1508 * if the offset originally points to the bytecode next to this 1509 * branch instruction. Otherwise, the bytecode would contain 1510 * dead code. It complicates the generation of StackMap and 1511 * StackMapTable. 1512 */ 1513 void adjustOffsets(int size, int nops) { 1514 if (defaultByte == size) 1515 defaultByte -= nops; 1516 1517 for (int i = 0; i < offsets.length; i++) 1518 if (offsets[i] == size) 1519 offsets[i] -= nops; 1520 } 1521 } 1522 1523 static class Table extends Switcher { 1524 int low, high; 1525 1526 Table(int pos, int defaultByte, int low, int high, int[] offsets) { 1527 super(pos, defaultByte, offsets); 1528 this.low = low; 1529 this.high = high; 1530 } 1531 1532 int write2(int dest, byte[] newcode) { 1533 ByteArray.write32bit(low, newcode, dest); 1534 ByteArray.write32bit(high, newcode, dest + 4); 1535 int n = offsets.length; 1536 dest += 8; 1537 for (int i = 0; i < n; i++) { 1538 ByteArray.write32bit(offsets[i], newcode, dest); 1539 dest += 4; 1540 } 1541 1542 return 8 + 4 * n; 1543 } 1544 1545 int tableSize() { return 8 + 4 * offsets.length; } 1546 } 1547 1548 static class Lookup extends Switcher { 1549 int[] matches; 1550 1551 Lookup(int pos, int defaultByte, int[] matches, int[] offsets) { 1552 super(pos, defaultByte, offsets); 1553 this.matches = matches; 1554 } 1555 1556 int write2(int dest, byte[] newcode) { 1557 int n = matches.length; 1558 ByteArray.write32bit(n, newcode, dest); 1559 dest += 4; 1560 for (int i = 0; i < n; i++) { 1561 ByteArray.write32bit(matches[i], newcode, dest); 1562 ByteArray.write32bit(offsets[i], newcode, dest + 4); 1563 dest += 8; 1564 } 1565 1566 return 4 + 8 * n; 1567 } 1568 1569 int tableSize() { return 4 + 8 * matches.length; } 1570 } 1571} 1572