1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.cf.code; 18 19 import com.android.dx.cf.iface.ParseException; 20 import com.android.dx.rop.cst.Constant; 21 import com.android.dx.rop.cst.ConstantPool; 22 import com.android.dx.rop.cst.CstDouble; 23 import com.android.dx.rop.cst.CstFloat; 24 import com.android.dx.rop.cst.CstInteger; 25 import com.android.dx.rop.cst.CstKnownNull; 26 import com.android.dx.rop.cst.CstLiteralBits; 27 import com.android.dx.rop.cst.CstLong; 28 import com.android.dx.rop.cst.CstType; 29 import com.android.dx.rop.type.Type; 30 import com.android.dx.util.Bits; 31 import com.android.dx.util.ByteArray; 32 import com.android.dx.util.Hex; 33 import java.util.ArrayList; 34 35 /** 36 * Bytecode array, which is part of a standard {@code Code} attribute. 37 */ 38 public final class BytecodeArray { 39 /** convenient no-op implementation of {@link Visitor} */ 40 public static final Visitor EMPTY_VISITOR = new BaseVisitor(); 41 42 /** {@code non-null;} underlying bytes */ 43 private final ByteArray bytes; 44 45 /** 46 * {@code non-null;} constant pool to use when resolving constant 47 * pool indices 48 */ 49 private final ConstantPool pool; 50 51 /** 52 * Constructs an instance. 53 * 54 * @param bytes {@code non-null;} underlying bytes 55 * @param pool {@code non-null;} constant pool to use when 56 * resolving constant pool indices 57 */ BytecodeArray(ByteArray bytes, ConstantPool pool)58 public BytecodeArray(ByteArray bytes, ConstantPool pool) { 59 if (bytes == null) { 60 throw new NullPointerException("bytes == null"); 61 } 62 63 if (pool == null) { 64 throw new NullPointerException("pool == null"); 65 } 66 67 this.bytes = bytes; 68 this.pool = pool; 69 } 70 71 /** 72 * Gets the underlying byte array. 73 * 74 * @return {@code non-null;} the byte array 75 */ getBytes()76 public ByteArray getBytes() { 77 return bytes; 78 } 79 80 /** 81 * Gets the size of the bytecode array, per se. 82 * 83 * @return {@code >= 0;} the length of the bytecode array 84 */ size()85 public int size() { 86 return bytes.size(); 87 } 88 89 /** 90 * Gets the total length of this structure in bytes, when included in 91 * a {@code Code} attribute. The returned value includes the 92 * array size plus four bytes for {@code code_length}. 93 * 94 * @return {@code >= 4;} the total length, in bytes 95 */ byteLength()96 public int byteLength() { 97 return 4 + bytes.size(); 98 } 99 100 /** 101 * Parses each instruction in the array, in order. 102 * 103 * @param visitor {@code null-ok;} visitor to call back to for 104 * each instruction 105 */ forEach(Visitor visitor)106 public void forEach(Visitor visitor) { 107 int sz = bytes.size(); 108 int at = 0; 109 110 while (at < sz) { 111 /* 112 * Don't record the previous offset here, so that we get to see the 113 * raw code that initializes the array 114 */ 115 at += parseInstruction(at, visitor); 116 } 117 } 118 119 /** 120 * Finds the offset to each instruction in the bytecode array. The 121 * result is a bit set with the offset of each opcode-per-se flipped on. 122 * 123 * @see Bits 124 * @return {@code non-null;} appropriately constructed bit set 125 */ getInstructionOffsets()126 public int[] getInstructionOffsets() { 127 int sz = bytes.size(); 128 int[] result = Bits.makeBitSet(sz); 129 int at = 0; 130 131 while (at < sz) { 132 Bits.set(result, at, true); 133 int length = parseInstruction(at, null); 134 at += length; 135 } 136 137 return result; 138 } 139 140 /** 141 * Processes the given "work set" by repeatedly finding the lowest bit 142 * in the set, clearing it, and parsing and visiting the instruction at 143 * the indicated offset (that is, the bit index), repeating until the 144 * work set is empty. It is expected that the visitor will regularly 145 * set new bits in the work set during the process. 146 * 147 * @param workSet {@code non-null;} the work set to process 148 * @param visitor {@code non-null;} visitor to call back to for 149 * each instruction 150 */ processWorkSet(int[] workSet, Visitor visitor)151 public void processWorkSet(int[] workSet, Visitor visitor) { 152 if (visitor == null) { 153 throw new NullPointerException("visitor == null"); 154 } 155 156 for (;;) { 157 int offset = Bits.findFirst(workSet, 0); 158 if (offset < 0) { 159 break; 160 } 161 Bits.clear(workSet, offset); 162 parseInstruction(offset, visitor); 163 visitor.setPreviousOffset(offset); 164 } 165 } 166 167 /** 168 * Parses the instruction at the indicated offset. Indicate the 169 * result by calling the visitor if supplied and by returning the 170 * number of bytes consumed by the instruction. 171 * 172 * <p>In order to simplify further processing, the opcodes passed 173 * to the visitor are canonicalized, altering the opcode to a more 174 * universal one and making formerly implicit arguments 175 * explicit. In particular:</p> 176 * 177 * <ul> 178 * <li>The opcodes to push literal constants of primitive types all become 179 * {@code ldc}. 180 * E.g., {@code fconst_0}, {@code sipush}, and 181 * {@code lconst_0} qualify for this treatment.</li> 182 * <li>{@code aconst_null} becomes {@code ldc} of a 183 * "known null."</li> 184 * <li>Shorthand local variable accessors become the corresponding 185 * longhand. E.g. {@code aload_2} becomes {@code aload}.</li> 186 * <li>{@code goto_w} and {@code jsr_w} become {@code goto} 187 * and {@code jsr} (respectively).</li> 188 * <li>{@code ldc_w} becomes {@code ldc}.</li> 189 * <li>{@code tableswitch} becomes {@code lookupswitch}. 190 * <li>Arithmetic, array, and value-returning ops are collapsed 191 * to the {@code int} variant opcode, with the {@code type} 192 * argument set to indicate the actual type. E.g., 193 * {@code fadd} becomes {@code iadd}, but 194 * {@code type} is passed as {@code Type.FLOAT} in that 195 * case. Similarly, {@code areturn} becomes 196 * {@code ireturn}. (However, {@code return} remains 197 * unchanged.</li> 198 * <li>Local variable access ops are collapsed to the {@code int} 199 * variant opcode, with the {@code type} argument set to indicate 200 * the actual type. E.g., {@code aload} becomes {@code iload}, 201 * but {@code type} is passed as {@code Type.OBJECT} in 202 * that case.</li> 203 * <li>Numeric conversion ops ({@code i2l}, etc.) are left alone 204 * to avoid too much confustion, but their {@code type} is 205 * the pushed type. E.g., {@code i2b} gets type 206 * {@code Type.INT}, and {@code f2d} gets type 207 * {@code Type.DOUBLE}. Other unaltered opcodes also get 208 * their pushed type. E.g., {@code arraylength} gets type 209 * {@code Type.INT}.</li> 210 * </ul> 211 * 212 * @param offset {@code >= 0, < bytes.size();} offset to the start of the 213 * instruction 214 * @param visitor {@code null-ok;} visitor to call back to 215 * @return the length of the instruction, in bytes 216 */ parseInstruction(int offset, Visitor visitor)217 public int parseInstruction(int offset, Visitor visitor) { 218 if (visitor == null) { 219 visitor = EMPTY_VISITOR; 220 } 221 222 try { 223 int opcode = bytes.getUnsignedByte(offset); 224 int info = ByteOps.opInfo(opcode); 225 int fmt = info & ByteOps.FMT_MASK; 226 227 switch (opcode) { 228 case ByteOps.NOP: { 229 visitor.visitNoArgs(opcode, offset, 1, Type.VOID); 230 return 1; 231 } 232 case ByteOps.ACONST_NULL: { 233 visitor.visitConstant(ByteOps.LDC, offset, 1, 234 CstKnownNull.THE_ONE, 0); 235 return 1; 236 } 237 case ByteOps.ICONST_M1: { 238 visitor.visitConstant(ByteOps.LDC, offset, 1, 239 CstInteger.VALUE_M1, -1); 240 return 1; 241 } 242 case ByteOps.ICONST_0: { 243 visitor.visitConstant(ByteOps.LDC, offset, 1, 244 CstInteger.VALUE_0, 0); 245 return 1; 246 } 247 case ByteOps.ICONST_1: { 248 visitor.visitConstant(ByteOps.LDC, offset, 1, 249 CstInteger.VALUE_1, 1); 250 return 1; 251 } 252 case ByteOps.ICONST_2: { 253 visitor.visitConstant(ByteOps.LDC, offset, 1, 254 CstInteger.VALUE_2, 2); 255 return 1; 256 } 257 case ByteOps.ICONST_3: { 258 visitor.visitConstant(ByteOps.LDC, offset, 1, 259 CstInteger.VALUE_3, 3); 260 return 1; 261 } 262 case ByteOps.ICONST_4: { 263 visitor.visitConstant(ByteOps.LDC, offset, 1, 264 CstInteger.VALUE_4, 4); 265 return 1; 266 } 267 case ByteOps.ICONST_5: { 268 visitor.visitConstant(ByteOps.LDC, offset, 1, 269 CstInteger.VALUE_5, 5); 270 return 1; 271 } 272 case ByteOps.LCONST_0: { 273 visitor.visitConstant(ByteOps.LDC, offset, 1, 274 CstLong.VALUE_0, 0); 275 return 1; 276 } 277 case ByteOps.LCONST_1: { 278 visitor.visitConstant(ByteOps.LDC, offset, 1, 279 CstLong.VALUE_1, 0); 280 return 1; 281 } 282 case ByteOps.FCONST_0: { 283 visitor.visitConstant(ByteOps.LDC, offset, 1, 284 CstFloat.VALUE_0, 0); 285 return 1; 286 } 287 case ByteOps.FCONST_1: { 288 visitor.visitConstant(ByteOps.LDC, offset, 1, 289 CstFloat.VALUE_1, 0); 290 return 1; 291 } 292 case ByteOps.FCONST_2: { 293 visitor.visitConstant(ByteOps.LDC, offset, 1, 294 CstFloat.VALUE_2, 0); 295 return 1; 296 } 297 case ByteOps.DCONST_0: { 298 visitor.visitConstant(ByteOps.LDC, offset, 1, 299 CstDouble.VALUE_0, 0); 300 return 1; 301 } 302 case ByteOps.DCONST_1: { 303 visitor.visitConstant(ByteOps.LDC, offset, 1, 304 CstDouble.VALUE_1, 0); 305 return 1; 306 } 307 case ByteOps.BIPUSH: { 308 int value = bytes.getByte(offset + 1); 309 visitor.visitConstant(ByteOps.LDC, offset, 2, 310 CstInteger.make(value), value); 311 return 2; 312 } 313 case ByteOps.SIPUSH: { 314 int value = bytes.getShort(offset + 1); 315 visitor.visitConstant(ByteOps.LDC, offset, 3, 316 CstInteger.make(value), value); 317 return 3; 318 } 319 case ByteOps.LDC: { 320 int idx = bytes.getUnsignedByte(offset + 1); 321 Constant cst = pool.get(idx); 322 int value = (cst instanceof CstInteger) ? 323 ((CstInteger) cst).getValue() : 0; 324 visitor.visitConstant(ByteOps.LDC, offset, 2, cst, value); 325 return 2; 326 } 327 case ByteOps.LDC_W: { 328 int idx = bytes.getUnsignedShort(offset + 1); 329 Constant cst = pool.get(idx); 330 int value = (cst instanceof CstInteger) ? 331 ((CstInteger) cst).getValue() : 0; 332 visitor.visitConstant(ByteOps.LDC, offset, 3, cst, value); 333 return 3; 334 } 335 case ByteOps.LDC2_W: { 336 int idx = bytes.getUnsignedShort(offset + 1); 337 Constant cst = pool.get(idx); 338 visitor.visitConstant(ByteOps.LDC2_W, offset, 3, cst, 0); 339 return 3; 340 } 341 case ByteOps.ILOAD: { 342 int idx = bytes.getUnsignedByte(offset + 1); 343 visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, 344 Type.INT, 0); 345 return 2; 346 } 347 case ByteOps.LLOAD: { 348 int idx = bytes.getUnsignedByte(offset + 1); 349 visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, 350 Type.LONG, 0); 351 return 2; 352 } 353 case ByteOps.FLOAD: { 354 int idx = bytes.getUnsignedByte(offset + 1); 355 visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, 356 Type.FLOAT, 0); 357 return 2; 358 } 359 case ByteOps.DLOAD: { 360 int idx = bytes.getUnsignedByte(offset + 1); 361 visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, 362 Type.DOUBLE, 0); 363 return 2; 364 } 365 case ByteOps.ALOAD: { 366 int idx = bytes.getUnsignedByte(offset + 1); 367 visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, 368 Type.OBJECT, 0); 369 return 2; 370 } 371 case ByteOps.ILOAD_0: 372 case ByteOps.ILOAD_1: 373 case ByteOps.ILOAD_2: 374 case ByteOps.ILOAD_3: { 375 int idx = opcode - ByteOps.ILOAD_0; 376 visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, 377 Type.INT, 0); 378 return 1; 379 } 380 case ByteOps.LLOAD_0: 381 case ByteOps.LLOAD_1: 382 case ByteOps.LLOAD_2: 383 case ByteOps.LLOAD_3: { 384 int idx = opcode - ByteOps.LLOAD_0; 385 visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, 386 Type.LONG, 0); 387 return 1; 388 } 389 case ByteOps.FLOAD_0: 390 case ByteOps.FLOAD_1: 391 case ByteOps.FLOAD_2: 392 case ByteOps.FLOAD_3: { 393 int idx = opcode - ByteOps.FLOAD_0; 394 visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, 395 Type.FLOAT, 0); 396 return 1; 397 } 398 case ByteOps.DLOAD_0: 399 case ByteOps.DLOAD_1: 400 case ByteOps.DLOAD_2: 401 case ByteOps.DLOAD_3: { 402 int idx = opcode - ByteOps.DLOAD_0; 403 visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, 404 Type.DOUBLE, 0); 405 return 1; 406 } 407 case ByteOps.ALOAD_0: 408 case ByteOps.ALOAD_1: 409 case ByteOps.ALOAD_2: 410 case ByteOps.ALOAD_3: { 411 int idx = opcode - ByteOps.ALOAD_0; 412 visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, 413 Type.OBJECT, 0); 414 return 1; 415 } 416 case ByteOps.IALOAD: { 417 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.INT); 418 return 1; 419 } 420 case ByteOps.LALOAD: { 421 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.LONG); 422 return 1; 423 } 424 case ByteOps.FALOAD: { 425 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, 426 Type.FLOAT); 427 return 1; 428 } 429 case ByteOps.DALOAD: { 430 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, 431 Type.DOUBLE); 432 return 1; 433 } 434 case ByteOps.AALOAD: { 435 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, 436 Type.OBJECT); 437 return 1; 438 } 439 case ByteOps.BALOAD: { 440 /* 441 * Note: This is a load from either a byte[] or a 442 * boolean[]. 443 */ 444 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.BYTE); 445 return 1; 446 } 447 case ByteOps.CALOAD: { 448 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.CHAR); 449 return 1; 450 } 451 case ByteOps.SALOAD: { 452 visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, 453 Type.SHORT); 454 return 1; 455 } 456 case ByteOps.ISTORE: { 457 int idx = bytes.getUnsignedByte(offset + 1); 458 visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, 459 Type.INT, 0); 460 return 2; 461 } 462 case ByteOps.LSTORE: { 463 int idx = bytes.getUnsignedByte(offset + 1); 464 visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, 465 Type.LONG, 0); 466 return 2; 467 } 468 case ByteOps.FSTORE: { 469 int idx = bytes.getUnsignedByte(offset + 1); 470 visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, 471 Type.FLOAT, 0); 472 return 2; 473 } 474 case ByteOps.DSTORE: { 475 int idx = bytes.getUnsignedByte(offset + 1); 476 visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, 477 Type.DOUBLE, 0); 478 return 2; 479 } 480 case ByteOps.ASTORE: { 481 int idx = bytes.getUnsignedByte(offset + 1); 482 visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, 483 Type.OBJECT, 0); 484 return 2; 485 } 486 case ByteOps.ISTORE_0: 487 case ByteOps.ISTORE_1: 488 case ByteOps.ISTORE_2: 489 case ByteOps.ISTORE_3: { 490 int idx = opcode - ByteOps.ISTORE_0; 491 visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, 492 Type.INT, 0); 493 return 1; 494 } 495 case ByteOps.LSTORE_0: 496 case ByteOps.LSTORE_1: 497 case ByteOps.LSTORE_2: 498 case ByteOps.LSTORE_3: { 499 int idx = opcode - ByteOps.LSTORE_0; 500 visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, 501 Type.LONG, 0); 502 return 1; 503 } 504 case ByteOps.FSTORE_0: 505 case ByteOps.FSTORE_1: 506 case ByteOps.FSTORE_2: 507 case ByteOps.FSTORE_3: { 508 int idx = opcode - ByteOps.FSTORE_0; 509 visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, 510 Type.FLOAT, 0); 511 return 1; 512 } 513 case ByteOps.DSTORE_0: 514 case ByteOps.DSTORE_1: 515 case ByteOps.DSTORE_2: 516 case ByteOps.DSTORE_3: { 517 int idx = opcode - ByteOps.DSTORE_0; 518 visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, 519 Type.DOUBLE, 0); 520 return 1; 521 } 522 case ByteOps.ASTORE_0: 523 case ByteOps.ASTORE_1: 524 case ByteOps.ASTORE_2: 525 case ByteOps.ASTORE_3: { 526 int idx = opcode - ByteOps.ASTORE_0; 527 visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, 528 Type.OBJECT, 0); 529 return 1; 530 } 531 case ByteOps.IASTORE: { 532 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.INT); 533 return 1; 534 } 535 case ByteOps.LASTORE: { 536 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, 537 Type.LONG); 538 return 1; 539 } 540 case ByteOps.FASTORE: { 541 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, 542 Type.FLOAT); 543 return 1; 544 } 545 case ByteOps.DASTORE: { 546 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, 547 Type.DOUBLE); 548 return 1; 549 } 550 case ByteOps.AASTORE: { 551 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, 552 Type.OBJECT); 553 return 1; 554 } 555 case ByteOps.BASTORE: { 556 /* 557 * Note: This is a load from either a byte[] or a 558 * boolean[]. 559 */ 560 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, 561 Type.BYTE); 562 return 1; 563 } 564 case ByteOps.CASTORE: { 565 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, 566 Type.CHAR); 567 return 1; 568 } 569 case ByteOps.SASTORE: { 570 visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, 571 Type.SHORT); 572 return 1; 573 } 574 case ByteOps.POP: 575 case ByteOps.POP2: 576 case ByteOps.DUP: 577 case ByteOps.DUP_X1: 578 case ByteOps.DUP_X2: 579 case ByteOps.DUP2: 580 case ByteOps.DUP2_X1: 581 case ByteOps.DUP2_X2: 582 case ByteOps.SWAP: { 583 visitor.visitNoArgs(opcode, offset, 1, Type.VOID); 584 return 1; 585 } 586 case ByteOps.IADD: 587 case ByteOps.ISUB: 588 case ByteOps.IMUL: 589 case ByteOps.IDIV: 590 case ByteOps.IREM: 591 case ByteOps.INEG: 592 case ByteOps.ISHL: 593 case ByteOps.ISHR: 594 case ByteOps.IUSHR: 595 case ByteOps.IAND: 596 case ByteOps.IOR: 597 case ByteOps.IXOR: { 598 visitor.visitNoArgs(opcode, offset, 1, Type.INT); 599 return 1; 600 } 601 case ByteOps.LADD: 602 case ByteOps.LSUB: 603 case ByteOps.LMUL: 604 case ByteOps.LDIV: 605 case ByteOps.LREM: 606 case ByteOps.LNEG: 607 case ByteOps.LSHL: 608 case ByteOps.LSHR: 609 case ByteOps.LUSHR: 610 case ByteOps.LAND: 611 case ByteOps.LOR: 612 case ByteOps.LXOR: { 613 /* 614 * It's "opcode - 1" because, conveniently enough, all 615 * these long ops are one past the int variants. 616 */ 617 visitor.visitNoArgs(opcode - 1, offset, 1, Type.LONG); 618 return 1; 619 } 620 case ByteOps.FADD: 621 case ByteOps.FSUB: 622 case ByteOps.FMUL: 623 case ByteOps.FDIV: 624 case ByteOps.FREM: 625 case ByteOps.FNEG: { 626 /* 627 * It's "opcode - 2" because, conveniently enough, all 628 * these float ops are two past the int variants. 629 */ 630 visitor.visitNoArgs(opcode - 2, offset, 1, Type.FLOAT); 631 return 1; 632 } 633 case ByteOps.DADD: 634 case ByteOps.DSUB: 635 case ByteOps.DMUL: 636 case ByteOps.DDIV: 637 case ByteOps.DREM: 638 case ByteOps.DNEG: { 639 /* 640 * It's "opcode - 3" because, conveniently enough, all 641 * these double ops are three past the int variants. 642 */ 643 visitor.visitNoArgs(opcode - 3, offset, 1, Type.DOUBLE); 644 return 1; 645 } 646 case ByteOps.IINC: { 647 int idx = bytes.getUnsignedByte(offset + 1); 648 int value = bytes.getByte(offset + 2); 649 visitor.visitLocal(opcode, offset, 3, idx, 650 Type.INT, value); 651 return 3; 652 } 653 case ByteOps.I2L: 654 case ByteOps.F2L: 655 case ByteOps.D2L: { 656 visitor.visitNoArgs(opcode, offset, 1, Type.LONG); 657 return 1; 658 } 659 case ByteOps.I2F: 660 case ByteOps.L2F: 661 case ByteOps.D2F: { 662 visitor.visitNoArgs(opcode, offset, 1, Type.FLOAT); 663 return 1; 664 } 665 case ByteOps.I2D: 666 case ByteOps.L2D: 667 case ByteOps.F2D: { 668 visitor.visitNoArgs(opcode, offset, 1, Type.DOUBLE); 669 return 1; 670 } 671 case ByteOps.L2I: 672 case ByteOps.F2I: 673 case ByteOps.D2I: 674 case ByteOps.I2B: 675 case ByteOps.I2C: 676 case ByteOps.I2S: 677 case ByteOps.LCMP: 678 case ByteOps.FCMPL: 679 case ByteOps.FCMPG: 680 case ByteOps.DCMPL: 681 case ByteOps.DCMPG: 682 case ByteOps.ARRAYLENGTH: { 683 visitor.visitNoArgs(opcode, offset, 1, Type.INT); 684 return 1; 685 } 686 case ByteOps.IFEQ: 687 case ByteOps.IFNE: 688 case ByteOps.IFLT: 689 case ByteOps.IFGE: 690 case ByteOps.IFGT: 691 case ByteOps.IFLE: 692 case ByteOps.IF_ICMPEQ: 693 case ByteOps.IF_ICMPNE: 694 case ByteOps.IF_ICMPLT: 695 case ByteOps.IF_ICMPGE: 696 case ByteOps.IF_ICMPGT: 697 case ByteOps.IF_ICMPLE: 698 case ByteOps.IF_ACMPEQ: 699 case ByteOps.IF_ACMPNE: 700 case ByteOps.GOTO: 701 case ByteOps.JSR: 702 case ByteOps.IFNULL: 703 case ByteOps.IFNONNULL: { 704 int target = offset + bytes.getShort(offset + 1); 705 visitor.visitBranch(opcode, offset, 3, target); 706 return 3; 707 } 708 case ByteOps.RET: { 709 int idx = bytes.getUnsignedByte(offset + 1); 710 visitor.visitLocal(opcode, offset, 2, idx, 711 Type.RETURN_ADDRESS, 0); 712 return 2; 713 } 714 case ByteOps.TABLESWITCH: { 715 return parseTableswitch(offset, visitor); 716 } 717 case ByteOps.LOOKUPSWITCH: { 718 return parseLookupswitch(offset, visitor); 719 } 720 case ByteOps.IRETURN: { 721 visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.INT); 722 return 1; 723 } 724 case ByteOps.LRETURN: { 725 visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, 726 Type.LONG); 727 return 1; 728 } 729 case ByteOps.FRETURN: { 730 visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, 731 Type.FLOAT); 732 return 1; 733 } 734 case ByteOps.DRETURN: { 735 visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, 736 Type.DOUBLE); 737 return 1; 738 } 739 case ByteOps.ARETURN: { 740 visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, 741 Type.OBJECT); 742 return 1; 743 } 744 case ByteOps.RETURN: 745 case ByteOps.ATHROW: 746 case ByteOps.MONITORENTER: 747 case ByteOps.MONITOREXIT: { 748 visitor.visitNoArgs(opcode, offset, 1, Type.VOID); 749 return 1; 750 } 751 case ByteOps.GETSTATIC: 752 case ByteOps.PUTSTATIC: 753 case ByteOps.GETFIELD: 754 case ByteOps.PUTFIELD: 755 case ByteOps.INVOKEVIRTUAL: 756 case ByteOps.INVOKESPECIAL: 757 case ByteOps.INVOKESTATIC: 758 case ByteOps.NEW: 759 case ByteOps.ANEWARRAY: 760 case ByteOps.CHECKCAST: 761 case ByteOps.INSTANCEOF: { 762 int idx = bytes.getUnsignedShort(offset + 1); 763 Constant cst = pool.get(idx); 764 visitor.visitConstant(opcode, offset, 3, cst, 0); 765 return 3; 766 } 767 case ByteOps.INVOKEINTERFACE: { 768 int idx = bytes.getUnsignedShort(offset + 1); 769 int count = bytes.getUnsignedByte(offset + 3); 770 int expectZero = bytes.getUnsignedByte(offset + 4); 771 Constant cst = pool.get(idx); 772 visitor.visitConstant(opcode, offset, 5, cst, 773 count | (expectZero << 8)); 774 return 5; 775 } 776 case ByteOps.INVOKEDYNAMIC: { 777 throw new ParseException("invokedynamic not supported"); 778 } 779 case ByteOps.NEWARRAY: { 780 return parseNewarray(offset, visitor); 781 } 782 case ByteOps.WIDE: { 783 return parseWide(offset, visitor); 784 } 785 case ByteOps.MULTIANEWARRAY: { 786 int idx = bytes.getUnsignedShort(offset + 1); 787 int dimensions = bytes.getUnsignedByte(offset + 3); 788 Constant cst = pool.get(idx); 789 visitor.visitConstant(opcode, offset, 4, cst, dimensions); 790 return 4; 791 } 792 case ByteOps.GOTO_W: 793 case ByteOps.JSR_W: { 794 int target = offset + bytes.getInt(offset + 1); 795 int newop = 796 (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO : 797 ByteOps.JSR; 798 visitor.visitBranch(newop, offset, 5, target); 799 return 5; 800 } 801 default: { 802 visitor.visitInvalid(opcode, offset, 1); 803 return 1; 804 } 805 } 806 } catch (SimException ex) { 807 ex.addContext("...at bytecode offset " + Hex.u4(offset)); 808 throw ex; 809 } catch (RuntimeException ex) { 810 SimException se = new SimException(ex); 811 se.addContext("...at bytecode offset " + Hex.u4(offset)); 812 throw se; 813 } 814 } 815 816 /** 817 * Helper to deal with {@code tableswitch}. 818 * 819 * @param offset the offset to the {@code tableswitch} opcode itself 820 * @param visitor {@code non-null;} visitor to use 821 * @return instruction length, in bytes 822 */ parseTableswitch(int offset, Visitor visitor)823 private int parseTableswitch(int offset, Visitor visitor) { 824 int at = (offset + 4) & ~3; // "at" skips the padding. 825 826 // Collect the padding. 827 int padding = 0; 828 for (int i = offset + 1; i < at; i++) { 829 padding = (padding << 8) | bytes.getUnsignedByte(i); 830 } 831 832 int defaultTarget = offset + bytes.getInt(at); 833 int low = bytes.getInt(at + 4); 834 int high = bytes.getInt(at + 8); 835 int count = high - low + 1; 836 at += 12; 837 838 if (low > high) { 839 throw new SimException("low / high inversion"); 840 } 841 842 SwitchList cases = new SwitchList(count); 843 for (int i = 0; i < count; i++) { 844 int target = offset + bytes.getInt(at); 845 at += 4; 846 cases.add(low + i, target); 847 } 848 cases.setDefaultTarget(defaultTarget); 849 cases.removeSuperfluousDefaults(); 850 cases.setImmutable(); 851 852 int length = at - offset; 853 visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases, 854 padding); 855 856 return length; 857 } 858 859 /** 860 * Helper to deal with {@code lookupswitch}. 861 * 862 * @param offset the offset to the {@code lookupswitch} opcode itself 863 * @param visitor {@code non-null;} visitor to use 864 * @return instruction length, in bytes 865 */ parseLookupswitch(int offset, Visitor visitor)866 private int parseLookupswitch(int offset, Visitor visitor) { 867 int at = (offset + 4) & ~3; // "at" skips the padding. 868 869 // Collect the padding. 870 int padding = 0; 871 for (int i = offset + 1; i < at; i++) { 872 padding = (padding << 8) | bytes.getUnsignedByte(i); 873 } 874 875 int defaultTarget = offset + bytes.getInt(at); 876 int npairs = bytes.getInt(at + 4); 877 at += 8; 878 879 SwitchList cases = new SwitchList(npairs); 880 for (int i = 0; i < npairs; i++) { 881 int match = bytes.getInt(at); 882 int target = offset + bytes.getInt(at + 4); 883 at += 8; 884 cases.add(match, target); 885 } 886 cases.setDefaultTarget(defaultTarget); 887 cases.removeSuperfluousDefaults(); 888 cases.setImmutable(); 889 890 int length = at - offset; 891 visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases, 892 padding); 893 894 return length; 895 } 896 897 /** 898 * Helper to deal with {@code newarray}. 899 * 900 * @param offset the offset to the {@code newarray} opcode itself 901 * @param visitor {@code non-null;} visitor to use 902 * @return instruction length, in bytes 903 */ parseNewarray(int offset, Visitor visitor)904 private int parseNewarray(int offset, Visitor visitor) { 905 int value = bytes.getUnsignedByte(offset + 1); 906 CstType type; 907 switch (value) { 908 case ByteOps.NEWARRAY_BOOLEAN: { 909 type = CstType.BOOLEAN_ARRAY; 910 break; 911 } 912 case ByteOps.NEWARRAY_CHAR: { 913 type = CstType.CHAR_ARRAY; 914 break; 915 } 916 case ByteOps.NEWARRAY_DOUBLE: { 917 type = CstType.DOUBLE_ARRAY; 918 break; 919 } 920 case ByteOps.NEWARRAY_FLOAT: { 921 type = CstType.FLOAT_ARRAY; 922 break; 923 } 924 case ByteOps.NEWARRAY_BYTE: { 925 type = CstType.BYTE_ARRAY; 926 break; 927 } 928 case ByteOps.NEWARRAY_SHORT: { 929 type = CstType.SHORT_ARRAY; 930 break; 931 } 932 case ByteOps.NEWARRAY_INT: { 933 type = CstType.INT_ARRAY; 934 break; 935 } 936 case ByteOps.NEWARRAY_LONG: { 937 type = CstType.LONG_ARRAY; 938 break; 939 } 940 default: { 941 throw new SimException("bad newarray code " + 942 Hex.u1(value)); 943 } 944 } 945 946 // Revisit the previous bytecode to find out the length of the array 947 int previousOffset = visitor.getPreviousOffset(); 948 ConstantParserVisitor constantVisitor = new ConstantParserVisitor(); 949 int arrayLength = 0; 950 951 /* 952 * For visitors that don't record the previous offset, -1 will be 953 * seen here 954 */ 955 if (previousOffset >= 0) { 956 parseInstruction(previousOffset, constantVisitor); 957 if (constantVisitor.cst instanceof CstInteger && 958 constantVisitor.length + previousOffset == offset) { 959 arrayLength = constantVisitor.value; 960 961 } 962 } 963 964 /* 965 * Try to match the array initialization idiom. For example, if the 966 * subsequent code is initializing an int array, we are expecting the 967 * following pattern repeatedly: 968 * dup 969 * push index 970 * push value 971 * *astore 972 * 973 * where the index value will be incrimented sequentially from 0 up. 974 */ 975 int nInit = 0; 976 int curOffset = offset+2; 977 int lastOffset = curOffset; 978 ArrayList<Constant> initVals = new ArrayList<Constant>(); 979 980 if (arrayLength != 0) { 981 while (true) { 982 boolean punt = false; 983 984 // First, check if the next bytecode is dup. 985 int nextByte = bytes.getUnsignedByte(curOffset++); 986 if (nextByte != ByteOps.DUP) 987 break; 988 989 /* 990 * Next, check if the expected array index is pushed to 991 * the stack. 992 */ 993 parseInstruction(curOffset, constantVisitor); 994 if (constantVisitor.length == 0 || 995 !(constantVisitor.cst instanceof CstInteger) || 996 constantVisitor.value != nInit) 997 break; 998 999 // Next, fetch the init value and record it. 1000 curOffset += constantVisitor.length; 1001 1002 /* 1003 * Next, find out what kind of constant is pushed onto 1004 * the stack. 1005 */ 1006 parseInstruction(curOffset, constantVisitor); 1007 if (constantVisitor.length == 0 || 1008 !(constantVisitor.cst instanceof CstLiteralBits)) 1009 break; 1010 1011 curOffset += constantVisitor.length; 1012 initVals.add(constantVisitor.cst); 1013 1014 nextByte = bytes.getUnsignedByte(curOffset++); 1015 // Now, check if the value is stored to the array properly. 1016 switch (value) { 1017 case ByteOps.NEWARRAY_BYTE: 1018 case ByteOps.NEWARRAY_BOOLEAN: { 1019 if (nextByte != ByteOps.BASTORE) { 1020 punt = true; 1021 } 1022 break; 1023 } 1024 case ByteOps.NEWARRAY_CHAR: { 1025 if (nextByte != ByteOps.CASTORE) { 1026 punt = true; 1027 } 1028 break; 1029 } 1030 case ByteOps.NEWARRAY_DOUBLE: { 1031 if (nextByte != ByteOps.DASTORE) { 1032 punt = true; 1033 } 1034 break; 1035 } 1036 case ByteOps.NEWARRAY_FLOAT: { 1037 if (nextByte != ByteOps.FASTORE) { 1038 punt = true; 1039 } 1040 break; 1041 } 1042 case ByteOps.NEWARRAY_SHORT: { 1043 if (nextByte != ByteOps.SASTORE) { 1044 punt = true; 1045 } 1046 break; 1047 } 1048 case ByteOps.NEWARRAY_INT: { 1049 if (nextByte != ByteOps.IASTORE) { 1050 punt = true; 1051 } 1052 break; 1053 } 1054 case ByteOps.NEWARRAY_LONG: { 1055 if (nextByte != ByteOps.LASTORE) { 1056 punt = true; 1057 } 1058 break; 1059 } 1060 default: 1061 punt = true; 1062 break; 1063 } 1064 if (punt) { 1065 break; 1066 } 1067 lastOffset = curOffset; 1068 nInit++; 1069 } 1070 } 1071 1072 /* 1073 * For singleton arrays it is still more economical to 1074 * generate the aput. 1075 */ 1076 if (nInit < 2 || nInit != arrayLength) { 1077 visitor.visitNewarray(offset, 2, type, null); 1078 return 2; 1079 } else { 1080 visitor.visitNewarray(offset, lastOffset - offset, type, initVals); 1081 return lastOffset - offset; 1082 } 1083 } 1084 1085 1086 /** 1087 * Helper to deal with {@code wide}. 1088 * 1089 * @param offset the offset to the {@code wide} opcode itself 1090 * @param visitor {@code non-null;} visitor to use 1091 * @return instruction length, in bytes 1092 */ parseWide(int offset, Visitor visitor)1093 private int parseWide(int offset, Visitor visitor) { 1094 int opcode = bytes.getUnsignedByte(offset + 1); 1095 int idx = bytes.getUnsignedShort(offset + 2); 1096 switch (opcode) { 1097 case ByteOps.ILOAD: { 1098 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1099 Type.INT, 0); 1100 return 4; 1101 } 1102 case ByteOps.LLOAD: { 1103 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1104 Type.LONG, 0); 1105 return 4; 1106 } 1107 case ByteOps.FLOAD: { 1108 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1109 Type.FLOAT, 0); 1110 return 4; 1111 } 1112 case ByteOps.DLOAD: { 1113 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1114 Type.DOUBLE, 0); 1115 return 4; 1116 } 1117 case ByteOps.ALOAD: { 1118 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1119 Type.OBJECT, 0); 1120 return 4; 1121 } 1122 case ByteOps.ISTORE: { 1123 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1124 Type.INT, 0); 1125 return 4; 1126 } 1127 case ByteOps.LSTORE: { 1128 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1129 Type.LONG, 0); 1130 return 4; 1131 } 1132 case ByteOps.FSTORE: { 1133 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1134 Type.FLOAT, 0); 1135 return 4; 1136 } 1137 case ByteOps.DSTORE: { 1138 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1139 Type.DOUBLE, 0); 1140 return 4; 1141 } 1142 case ByteOps.ASTORE: { 1143 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1144 Type.OBJECT, 0); 1145 return 4; 1146 } 1147 case ByteOps.RET: { 1148 visitor.visitLocal(opcode, offset, 4, idx, 1149 Type.RETURN_ADDRESS, 0); 1150 return 4; 1151 } 1152 case ByteOps.IINC: { 1153 int value = bytes.getShort(offset + 4); 1154 visitor.visitLocal(opcode, offset, 6, idx, 1155 Type.INT, value); 1156 return 6; 1157 } 1158 default: { 1159 visitor.visitInvalid(ByteOps.WIDE, offset, 1); 1160 return 1; 1161 } 1162 } 1163 } 1164 1165 /** 1166 * Instruction visitor interface. 1167 */ 1168 public interface Visitor { 1169 /** 1170 * Visits an invalid instruction. 1171 * 1172 * @param opcode the opcode 1173 * @param offset offset to the instruction 1174 * @param length length of the instruction, in bytes 1175 */ visitInvalid(int opcode, int offset, int length)1176 public void visitInvalid(int opcode, int offset, int length); 1177 1178 /** 1179 * Visits an instruction which has no inline arguments 1180 * (implicit or explicit). 1181 * 1182 * @param opcode the opcode 1183 * @param offset offset to the instruction 1184 * @param length length of the instruction, in bytes 1185 * @param type {@code non-null;} type the instruction operates on 1186 */ visitNoArgs(int opcode, int offset, int length, Type type)1187 public void visitNoArgs(int opcode, int offset, int length, 1188 Type type); 1189 1190 /** 1191 * Visits an instruction which has a local variable index argument. 1192 * 1193 * @param opcode the opcode 1194 * @param offset offset to the instruction 1195 * @param length length of the instruction, in bytes 1196 * @param idx the local variable index 1197 * @param type {@code non-null;} the type of the accessed value 1198 * @param value additional literal integer argument, if salient (i.e., 1199 * for {@code iinc}) 1200 */ visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1201 public void visitLocal(int opcode, int offset, int length, 1202 int idx, Type type, int value); 1203 1204 /** 1205 * Visits an instruction which has a (possibly synthetic) 1206 * constant argument, and possibly also an 1207 * additional literal integer argument. In the case of 1208 * {@code multianewarray}, the argument is the count of 1209 * dimensions. In the case of {@code invokeinterface}, 1210 * the argument is the parameter count or'ed with the 1211 * should-be-zero value left-shifted by 8. In the case of entries 1212 * of type {@code int}, the {@code value} field always 1213 * holds the raw value (for convenience of clients). 1214 * 1215 * <p><b>Note:</b> In order to avoid giving it a barely-useful 1216 * visitor all its own, {@code newarray} also uses this 1217 * form, passing {@code value} as the array type code and 1218 * {@code cst} as a {@link CstType} instance 1219 * corresponding to the array type.</p> 1220 * 1221 * @param opcode the opcode 1222 * @param offset offset to the instruction 1223 * @param length length of the instruction, in bytes 1224 * @param cst {@code non-null;} the constant 1225 * @param value additional literal integer argument, if salient 1226 * (ignore if not) 1227 */ visitConstant(int opcode, int offset, int length, Constant cst, int value)1228 public void visitConstant(int opcode, int offset, int length, 1229 Constant cst, int value); 1230 1231 /** 1232 * Visits an instruction which has a branch target argument. 1233 * 1234 * @param opcode the opcode 1235 * @param offset offset to the instruction 1236 * @param length length of the instruction, in bytes 1237 * @param target the absolute (not relative) branch target 1238 */ visitBranch(int opcode, int offset, int length, int target)1239 public void visitBranch(int opcode, int offset, int length, 1240 int target); 1241 1242 /** 1243 * Visits a switch instruction. 1244 * 1245 * @param opcode the opcode 1246 * @param offset offset to the instruction 1247 * @param length length of the instruction, in bytes 1248 * @param cases {@code non-null;} list of (value, target) 1249 * pairs, plus the default target 1250 * @param padding the bytes found in the padding area (if any), 1251 * packed 1252 */ visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1253 public void visitSwitch(int opcode, int offset, int length, 1254 SwitchList cases, int padding); 1255 1256 /** 1257 * Visits a newarray instruction. 1258 * 1259 * @param offset offset to the instruction 1260 * @param length length of the instruction, in bytes 1261 * @param type {@code non-null;} the type of the array 1262 * @param initVals {@code non-null;} list of bytecode offsets 1263 * for init values 1264 */ visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1265 public void visitNewarray(int offset, int length, CstType type, 1266 ArrayList<Constant> initVals); 1267 1268 /** 1269 * Set previous bytecode offset 1270 * @param offset offset of the previous fully parsed bytecode 1271 */ setPreviousOffset(int offset)1272 public void setPreviousOffset(int offset); 1273 1274 /** 1275 * Get previous bytecode offset 1276 * @return return the recored offset of the previous bytecode 1277 */ getPreviousOffset()1278 public int getPreviousOffset(); 1279 } 1280 1281 /** 1282 * Base implementation of {@link Visitor}, which has empty method 1283 * bodies for all methods. 1284 */ 1285 public static class BaseVisitor implements Visitor { 1286 1287 /** offset of the previously parsed bytecode */ 1288 private int previousOffset; 1289 BaseVisitor()1290 BaseVisitor() { 1291 previousOffset = -1; 1292 } 1293 1294 /** {@inheritDoc} */ visitInvalid(int opcode, int offset, int length)1295 public void visitInvalid(int opcode, int offset, int length) { 1296 // This space intentionally left blank. 1297 } 1298 1299 /** {@inheritDoc} */ visitNoArgs(int opcode, int offset, int length, Type type)1300 public void visitNoArgs(int opcode, int offset, int length, 1301 Type type) { 1302 // This space intentionally left blank. 1303 } 1304 1305 /** {@inheritDoc} */ visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1306 public void visitLocal(int opcode, int offset, int length, 1307 int idx, Type type, int value) { 1308 // This space intentionally left blank. 1309 } 1310 1311 /** {@inheritDoc} */ visitConstant(int opcode, int offset, int length, Constant cst, int value)1312 public void visitConstant(int opcode, int offset, int length, 1313 Constant cst, int value) { 1314 // This space intentionally left blank. 1315 } 1316 1317 /** {@inheritDoc} */ visitBranch(int opcode, int offset, int length, int target)1318 public void visitBranch(int opcode, int offset, int length, 1319 int target) { 1320 // This space intentionally left blank. 1321 } 1322 1323 /** {@inheritDoc} */ visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1324 public void visitSwitch(int opcode, int offset, int length, 1325 SwitchList cases, int padding) { 1326 // This space intentionally left blank. 1327 } 1328 1329 /** {@inheritDoc} */ visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initValues)1330 public void visitNewarray(int offset, int length, CstType type, 1331 ArrayList<Constant> initValues) { 1332 // This space intentionally left blank. 1333 } 1334 1335 /** {@inheritDoc} */ setPreviousOffset(int offset)1336 public void setPreviousOffset(int offset) { 1337 previousOffset = offset; 1338 } 1339 1340 /** {@inheritDoc} */ getPreviousOffset()1341 public int getPreviousOffset() { 1342 return previousOffset; 1343 } 1344 } 1345 1346 /** 1347 * Implementation of {@link Visitor}, which just pays attention 1348 * to constant values. 1349 */ 1350 class ConstantParserVisitor extends BaseVisitor { 1351 Constant cst; 1352 int length; 1353 int value; 1354 1355 /** Empty constructor */ ConstantParserVisitor()1356 ConstantParserVisitor() { 1357 } 1358 clear()1359 private void clear() { 1360 length = 0; 1361 } 1362 1363 /** {@inheritDoc} */ 1364 @Override visitInvalid(int opcode, int offset, int length)1365 public void visitInvalid(int opcode, int offset, int length) { 1366 clear(); 1367 } 1368 1369 /** {@inheritDoc} */ 1370 @Override visitNoArgs(int opcode, int offset, int length, Type type)1371 public void visitNoArgs(int opcode, int offset, int length, 1372 Type type) { 1373 clear(); 1374 } 1375 1376 /** {@inheritDoc} */ 1377 @Override visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1378 public void visitLocal(int opcode, int offset, int length, 1379 int idx, Type type, int value) { 1380 clear(); 1381 } 1382 1383 /** {@inheritDoc} */ 1384 @Override visitConstant(int opcode, int offset, int length, Constant cst, int value)1385 public void visitConstant(int opcode, int offset, int length, 1386 Constant cst, int value) { 1387 this.cst = cst; 1388 this.length = length; 1389 this.value = value; 1390 } 1391 1392 /** {@inheritDoc} */ 1393 @Override visitBranch(int opcode, int offset, int length, int target)1394 public void visitBranch(int opcode, int offset, int length, 1395 int target) { 1396 clear(); 1397 } 1398 1399 /** {@inheritDoc} */ 1400 @Override visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1401 public void visitSwitch(int opcode, int offset, int length, 1402 SwitchList cases, int padding) { 1403 clear(); 1404 } 1405 1406 /** {@inheritDoc} */ 1407 @Override visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1408 public void visitNewarray(int offset, int length, CstType type, 1409 ArrayList<Constant> initVals) { 1410 clear(); 1411 } 1412 1413 /** {@inheritDoc} */ 1414 @Override setPreviousOffset(int offset)1415 public void setPreviousOffset(int offset) { 1416 // Intentionally left empty 1417 } 1418 1419 /** {@inheritDoc} */ 1420 @Override getPreviousOffset()1421 public int getPreviousOffset() { 1422 // Intentionally left empty 1423 return -1; 1424 } 1425 } 1426 } 1427