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.rop.cst.Constant; 20 import com.android.dx.rop.cst.ConstantPool; 21 import com.android.dx.rop.cst.CstDouble; 22 import com.android.dx.rop.cst.CstFloat; 23 import com.android.dx.rop.cst.CstInteger; 24 import com.android.dx.rop.cst.CstInvokeDynamic; 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 int idx = bytes.getUnsignedShort(offset + 1); 778 // Skip to must-be-zero bytes at offsets 3 and 4 779 CstInvokeDynamic cstInvokeDynamic = (CstInvokeDynamic) pool.get(idx); 780 visitor.visitConstant(opcode, offset, 5, cstInvokeDynamic, 0); 781 return 5; 782 } 783 case ByteOps.NEWARRAY: { 784 return parseNewarray(offset, visitor); 785 } 786 case ByteOps.WIDE: { 787 return parseWide(offset, visitor); 788 } 789 case ByteOps.MULTIANEWARRAY: { 790 int idx = bytes.getUnsignedShort(offset + 1); 791 int dimensions = bytes.getUnsignedByte(offset + 3); 792 Constant cst = pool.get(idx); 793 visitor.visitConstant(opcode, offset, 4, cst, dimensions); 794 return 4; 795 } 796 case ByteOps.GOTO_W: 797 case ByteOps.JSR_W: { 798 int target = offset + bytes.getInt(offset + 1); 799 int newop = 800 (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO : 801 ByteOps.JSR; 802 visitor.visitBranch(newop, offset, 5, target); 803 return 5; 804 } 805 default: { 806 visitor.visitInvalid(opcode, offset, 1); 807 return 1; 808 } 809 } 810 } catch (SimException ex) { 811 ex.addContext("...at bytecode offset " + Hex.u4(offset)); 812 throw ex; 813 } catch (RuntimeException ex) { 814 SimException se = new SimException(ex); 815 se.addContext("...at bytecode offset " + Hex.u4(offset)); 816 throw se; 817 } 818 } 819 820 /** 821 * Helper to deal with {@code tableswitch}. 822 * 823 * @param offset the offset to the {@code tableswitch} opcode itself 824 * @param visitor {@code non-null;} visitor to use 825 * @return instruction length, in bytes 826 */ parseTableswitch(int offset, Visitor visitor)827 private int parseTableswitch(int offset, Visitor visitor) { 828 int at = (offset + 4) & ~3; // "at" skips the padding. 829 830 // Collect the padding. 831 int padding = 0; 832 for (int i = offset + 1; i < at; i++) { 833 padding = (padding << 8) | bytes.getUnsignedByte(i); 834 } 835 836 int defaultTarget = offset + bytes.getInt(at); 837 int low = bytes.getInt(at + 4); 838 int high = bytes.getInt(at + 8); 839 int count = high - low + 1; 840 at += 12; 841 842 if (low > high) { 843 throw new SimException("low / high inversion"); 844 } 845 846 SwitchList cases = new SwitchList(count); 847 for (int i = 0; i < count; i++) { 848 int target = offset + bytes.getInt(at); 849 at += 4; 850 cases.add(low + i, target); 851 } 852 cases.setDefaultTarget(defaultTarget); 853 cases.removeSuperfluousDefaults(); 854 cases.setImmutable(); 855 856 int length = at - offset; 857 visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases, 858 padding); 859 860 return length; 861 } 862 863 /** 864 * Helper to deal with {@code lookupswitch}. 865 * 866 * @param offset the offset to the {@code lookupswitch} opcode itself 867 * @param visitor {@code non-null;} visitor to use 868 * @return instruction length, in bytes 869 */ parseLookupswitch(int offset, Visitor visitor)870 private int parseLookupswitch(int offset, Visitor visitor) { 871 int at = (offset + 4) & ~3; // "at" skips the padding. 872 873 // Collect the padding. 874 int padding = 0; 875 for (int i = offset + 1; i < at; i++) { 876 padding = (padding << 8) | bytes.getUnsignedByte(i); 877 } 878 879 int defaultTarget = offset + bytes.getInt(at); 880 int npairs = bytes.getInt(at + 4); 881 at += 8; 882 883 SwitchList cases = new SwitchList(npairs); 884 for (int i = 0; i < npairs; i++) { 885 int match = bytes.getInt(at); 886 int target = offset + bytes.getInt(at + 4); 887 at += 8; 888 cases.add(match, target); 889 } 890 cases.setDefaultTarget(defaultTarget); 891 cases.removeSuperfluousDefaults(); 892 cases.setImmutable(); 893 894 int length = at - offset; 895 visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases, 896 padding); 897 898 return length; 899 } 900 901 /** 902 * Helper to deal with {@code newarray}. 903 * 904 * @param offset the offset to the {@code newarray} opcode itself 905 * @param visitor {@code non-null;} visitor to use 906 * @return instruction length, in bytes 907 */ parseNewarray(int offset, Visitor visitor)908 private int parseNewarray(int offset, Visitor visitor) { 909 int value = bytes.getUnsignedByte(offset + 1); 910 CstType type; 911 switch (value) { 912 case ByteOps.NEWARRAY_BOOLEAN: { 913 type = CstType.BOOLEAN_ARRAY; 914 break; 915 } 916 case ByteOps.NEWARRAY_CHAR: { 917 type = CstType.CHAR_ARRAY; 918 break; 919 } 920 case ByteOps.NEWARRAY_DOUBLE: { 921 type = CstType.DOUBLE_ARRAY; 922 break; 923 } 924 case ByteOps.NEWARRAY_FLOAT: { 925 type = CstType.FLOAT_ARRAY; 926 break; 927 } 928 case ByteOps.NEWARRAY_BYTE: { 929 type = CstType.BYTE_ARRAY; 930 break; 931 } 932 case ByteOps.NEWARRAY_SHORT: { 933 type = CstType.SHORT_ARRAY; 934 break; 935 } 936 case ByteOps.NEWARRAY_INT: { 937 type = CstType.INT_ARRAY; 938 break; 939 } 940 case ByteOps.NEWARRAY_LONG: { 941 type = CstType.LONG_ARRAY; 942 break; 943 } 944 default: { 945 throw new SimException("bad newarray code " + 946 Hex.u1(value)); 947 } 948 } 949 950 // Revisit the previous bytecode to find out the length of the array 951 int previousOffset = visitor.getPreviousOffset(); 952 ConstantParserVisitor constantVisitor = new ConstantParserVisitor(); 953 int arrayLength = 0; 954 955 /* 956 * For visitors that don't record the previous offset, -1 will be 957 * seen here 958 */ 959 if (previousOffset >= 0) { 960 parseInstruction(previousOffset, constantVisitor); 961 if (constantVisitor.cst instanceof CstInteger && 962 constantVisitor.length + previousOffset == offset) { 963 arrayLength = constantVisitor.value; 964 965 } 966 } 967 968 /* 969 * Try to match the array initialization idiom. For example, if the 970 * subsequent code is initializing an int array, we are expecting the 971 * following pattern repeatedly: 972 * dup 973 * push index 974 * push value 975 * *astore 976 * 977 * where the index value will be incrimented sequentially from 0 up. 978 */ 979 int nInit = 0; 980 int curOffset = offset+2; 981 int lastOffset = curOffset; 982 ArrayList<Constant> initVals = new ArrayList<Constant>(); 983 984 if (arrayLength != 0) { 985 while (true) { 986 boolean punt = false; 987 988 // First, check if the next bytecode is dup. 989 int nextByte = bytes.getUnsignedByte(curOffset++); 990 if (nextByte != ByteOps.DUP) 991 break; 992 993 /* 994 * Next, check if the expected array index is pushed to 995 * the stack. 996 */ 997 parseInstruction(curOffset, constantVisitor); 998 if (constantVisitor.length == 0 || 999 !(constantVisitor.cst instanceof CstInteger) || 1000 constantVisitor.value != nInit) 1001 break; 1002 1003 // Next, fetch the init value and record it. 1004 curOffset += constantVisitor.length; 1005 1006 /* 1007 * Next, find out what kind of constant is pushed onto 1008 * the stack. 1009 */ 1010 parseInstruction(curOffset, constantVisitor); 1011 if (constantVisitor.length == 0 || 1012 !(constantVisitor.cst instanceof CstLiteralBits)) 1013 break; 1014 1015 curOffset += constantVisitor.length; 1016 initVals.add(constantVisitor.cst); 1017 1018 nextByte = bytes.getUnsignedByte(curOffset++); 1019 // Now, check if the value is stored to the array properly. 1020 switch (value) { 1021 case ByteOps.NEWARRAY_BYTE: 1022 case ByteOps.NEWARRAY_BOOLEAN: { 1023 if (nextByte != ByteOps.BASTORE) { 1024 punt = true; 1025 } 1026 break; 1027 } 1028 case ByteOps.NEWARRAY_CHAR: { 1029 if (nextByte != ByteOps.CASTORE) { 1030 punt = true; 1031 } 1032 break; 1033 } 1034 case ByteOps.NEWARRAY_DOUBLE: { 1035 if (nextByte != ByteOps.DASTORE) { 1036 punt = true; 1037 } 1038 break; 1039 } 1040 case ByteOps.NEWARRAY_FLOAT: { 1041 if (nextByte != ByteOps.FASTORE) { 1042 punt = true; 1043 } 1044 break; 1045 } 1046 case ByteOps.NEWARRAY_SHORT: { 1047 if (nextByte != ByteOps.SASTORE) { 1048 punt = true; 1049 } 1050 break; 1051 } 1052 case ByteOps.NEWARRAY_INT: { 1053 if (nextByte != ByteOps.IASTORE) { 1054 punt = true; 1055 } 1056 break; 1057 } 1058 case ByteOps.NEWARRAY_LONG: { 1059 if (nextByte != ByteOps.LASTORE) { 1060 punt = true; 1061 } 1062 break; 1063 } 1064 default: 1065 punt = true; 1066 break; 1067 } 1068 if (punt) { 1069 break; 1070 } 1071 lastOffset = curOffset; 1072 nInit++; 1073 } 1074 } 1075 1076 /* 1077 * For singleton arrays it is still more economical to 1078 * generate the aput. 1079 */ 1080 if (nInit < 2 || nInit != arrayLength) { 1081 visitor.visitNewarray(offset, 2, type, null); 1082 return 2; 1083 } else { 1084 visitor.visitNewarray(offset, lastOffset - offset, type, initVals); 1085 return lastOffset - offset; 1086 } 1087 } 1088 1089 1090 /** 1091 * Helper to deal with {@code wide}. 1092 * 1093 * @param offset the offset to the {@code wide} opcode itself 1094 * @param visitor {@code non-null;} visitor to use 1095 * @return instruction length, in bytes 1096 */ parseWide(int offset, Visitor visitor)1097 private int parseWide(int offset, Visitor visitor) { 1098 int opcode = bytes.getUnsignedByte(offset + 1); 1099 int idx = bytes.getUnsignedShort(offset + 2); 1100 switch (opcode) { 1101 case ByteOps.ILOAD: { 1102 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1103 Type.INT, 0); 1104 return 4; 1105 } 1106 case ByteOps.LLOAD: { 1107 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1108 Type.LONG, 0); 1109 return 4; 1110 } 1111 case ByteOps.FLOAD: { 1112 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1113 Type.FLOAT, 0); 1114 return 4; 1115 } 1116 case ByteOps.DLOAD: { 1117 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1118 Type.DOUBLE, 0); 1119 return 4; 1120 } 1121 case ByteOps.ALOAD: { 1122 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, 1123 Type.OBJECT, 0); 1124 return 4; 1125 } 1126 case ByteOps.ISTORE: { 1127 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1128 Type.INT, 0); 1129 return 4; 1130 } 1131 case ByteOps.LSTORE: { 1132 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1133 Type.LONG, 0); 1134 return 4; 1135 } 1136 case ByteOps.FSTORE: { 1137 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1138 Type.FLOAT, 0); 1139 return 4; 1140 } 1141 case ByteOps.DSTORE: { 1142 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1143 Type.DOUBLE, 0); 1144 return 4; 1145 } 1146 case ByteOps.ASTORE: { 1147 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, 1148 Type.OBJECT, 0); 1149 return 4; 1150 } 1151 case ByteOps.RET: { 1152 visitor.visitLocal(opcode, offset, 4, idx, 1153 Type.RETURN_ADDRESS, 0); 1154 return 4; 1155 } 1156 case ByteOps.IINC: { 1157 int value = bytes.getShort(offset + 4); 1158 visitor.visitLocal(opcode, offset, 6, idx, 1159 Type.INT, value); 1160 return 6; 1161 } 1162 default: { 1163 visitor.visitInvalid(ByteOps.WIDE, offset, 1); 1164 return 1; 1165 } 1166 } 1167 } 1168 1169 /** 1170 * Instruction visitor interface. 1171 */ 1172 public interface Visitor { 1173 /** 1174 * Visits an invalid instruction. 1175 * 1176 * @param opcode the opcode 1177 * @param offset offset to the instruction 1178 * @param length length of the instruction, in bytes 1179 */ visitInvalid(int opcode, int offset, int length)1180 public void visitInvalid(int opcode, int offset, int length); 1181 1182 /** 1183 * Visits an instruction which has no inline arguments 1184 * (implicit or explicit). 1185 * 1186 * @param opcode the opcode 1187 * @param offset offset to the instruction 1188 * @param length length of the instruction, in bytes 1189 * @param type {@code non-null;} type the instruction operates on 1190 */ visitNoArgs(int opcode, int offset, int length, Type type)1191 public void visitNoArgs(int opcode, int offset, int length, 1192 Type type); 1193 1194 /** 1195 * Visits an instruction which has a local variable index argument. 1196 * 1197 * @param opcode the opcode 1198 * @param offset offset to the instruction 1199 * @param length length of the instruction, in bytes 1200 * @param idx the local variable index 1201 * @param type {@code non-null;} the type of the accessed value 1202 * @param value additional literal integer argument, if salient (i.e., 1203 * for {@code iinc}) 1204 */ visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1205 public void visitLocal(int opcode, int offset, int length, 1206 int idx, Type type, int value); 1207 1208 /** 1209 * Visits an instruction which has a (possibly synthetic) 1210 * constant argument, and possibly also an 1211 * additional literal integer argument. In the case of 1212 * {@code multianewarray}, the argument is the count of 1213 * dimensions. In the case of {@code invokeinterface}, 1214 * the argument is the parameter count or'ed with the 1215 * should-be-zero value left-shifted by 8. In the case of entries 1216 * of type {@code int}, the {@code value} field always 1217 * holds the raw value (for convenience of clients). 1218 * 1219 * <p><b>Note:</b> In order to avoid giving it a barely-useful 1220 * visitor all its own, {@code newarray} also uses this 1221 * form, passing {@code value} as the array type code and 1222 * {@code cst} as a {@link CstType} instance 1223 * corresponding to the array type.</p> 1224 * 1225 * @param opcode the opcode 1226 * @param offset offset to the instruction 1227 * @param length length of the instruction, in bytes 1228 * @param cst {@code non-null;} the constant 1229 * @param value additional literal integer argument, if salient 1230 * (ignore if not) 1231 */ visitConstant(int opcode, int offset, int length, Constant cst, int value)1232 public void visitConstant(int opcode, int offset, int length, 1233 Constant cst, int value); 1234 1235 /** 1236 * Visits an instruction which has a branch target argument. 1237 * 1238 * @param opcode the opcode 1239 * @param offset offset to the instruction 1240 * @param length length of the instruction, in bytes 1241 * @param target the absolute (not relative) branch target 1242 */ visitBranch(int opcode, int offset, int length, int target)1243 public void visitBranch(int opcode, int offset, int length, 1244 int target); 1245 1246 /** 1247 * Visits a switch instruction. 1248 * 1249 * @param opcode the opcode 1250 * @param offset offset to the instruction 1251 * @param length length of the instruction, in bytes 1252 * @param cases {@code non-null;} list of (value, target) 1253 * pairs, plus the default target 1254 * @param padding the bytes found in the padding area (if any), 1255 * packed 1256 */ visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1257 public void visitSwitch(int opcode, int offset, int length, 1258 SwitchList cases, int padding); 1259 1260 /** 1261 * Visits a newarray instruction. 1262 * 1263 * @param offset offset to the instruction 1264 * @param length length of the instruction, in bytes 1265 * @param type {@code non-null;} the type of the array 1266 * @param initVals {@code non-null;} list of bytecode offsets 1267 * for init values 1268 */ visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1269 public void visitNewarray(int offset, int length, CstType type, 1270 ArrayList<Constant> initVals); 1271 1272 /** 1273 * Set previous bytecode offset 1274 * @param offset offset of the previous fully parsed bytecode 1275 */ setPreviousOffset(int offset)1276 public void setPreviousOffset(int offset); 1277 1278 /** 1279 * Get previous bytecode offset 1280 * @return return the recored offset of the previous bytecode 1281 */ getPreviousOffset()1282 public int getPreviousOffset(); 1283 } 1284 1285 /** 1286 * Base implementation of {@link Visitor}, which has empty method 1287 * bodies for all methods. 1288 */ 1289 public static class BaseVisitor implements Visitor { 1290 1291 /** offset of the previously parsed bytecode */ 1292 private int previousOffset; 1293 BaseVisitor()1294 BaseVisitor() { 1295 previousOffset = -1; 1296 } 1297 1298 /** {@inheritDoc} */ 1299 @Override visitInvalid(int opcode, int offset, int length)1300 public void visitInvalid(int opcode, int offset, int length) { 1301 // This space intentionally left blank. 1302 } 1303 1304 /** {@inheritDoc} */ 1305 @Override visitNoArgs(int opcode, int offset, int length, Type type)1306 public void visitNoArgs(int opcode, int offset, int length, 1307 Type type) { 1308 // This space intentionally left blank. 1309 } 1310 1311 /** {@inheritDoc} */ 1312 @Override visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1313 public void visitLocal(int opcode, int offset, int length, 1314 int idx, Type type, int value) { 1315 // This space intentionally left blank. 1316 } 1317 1318 /** {@inheritDoc} */ 1319 @Override visitConstant(int opcode, int offset, int length, Constant cst, int value)1320 public void visitConstant(int opcode, int offset, int length, 1321 Constant cst, int value) { 1322 // This space intentionally left blank. 1323 } 1324 1325 /** {@inheritDoc} */ 1326 @Override visitBranch(int opcode, int offset, int length, int target)1327 public void visitBranch(int opcode, int offset, int length, 1328 int target) { 1329 // This space intentionally left blank. 1330 } 1331 1332 /** {@inheritDoc} */ 1333 @Override visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1334 public void visitSwitch(int opcode, int offset, int length, 1335 SwitchList cases, int padding) { 1336 // This space intentionally left blank. 1337 } 1338 1339 /** {@inheritDoc} */ 1340 @Override visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initValues)1341 public void visitNewarray(int offset, int length, CstType type, 1342 ArrayList<Constant> initValues) { 1343 // This space intentionally left blank. 1344 } 1345 1346 /** {@inheritDoc} */ 1347 @Override setPreviousOffset(int offset)1348 public void setPreviousOffset(int offset) { 1349 previousOffset = offset; 1350 } 1351 1352 /** {@inheritDoc} */ 1353 @Override getPreviousOffset()1354 public int getPreviousOffset() { 1355 return previousOffset; 1356 } 1357 } 1358 1359 /** 1360 * Implementation of {@link Visitor}, which just pays attention 1361 * to constant values. 1362 */ 1363 class ConstantParserVisitor extends BaseVisitor { 1364 Constant cst; 1365 int length; 1366 int value; 1367 1368 /** Empty constructor */ ConstantParserVisitor()1369 ConstantParserVisitor() { 1370 } 1371 clear()1372 private void clear() { 1373 length = 0; 1374 } 1375 1376 /** {@inheritDoc} */ 1377 @Override visitInvalid(int opcode, int offset, int length)1378 public void visitInvalid(int opcode, int offset, int length) { 1379 clear(); 1380 } 1381 1382 /** {@inheritDoc} */ 1383 @Override visitNoArgs(int opcode, int offset, int length, Type type)1384 public void visitNoArgs(int opcode, int offset, int length, 1385 Type type) { 1386 clear(); 1387 } 1388 1389 /** {@inheritDoc} */ 1390 @Override visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1391 public void visitLocal(int opcode, int offset, int length, 1392 int idx, Type type, int value) { 1393 clear(); 1394 } 1395 1396 /** {@inheritDoc} */ 1397 @Override visitConstant(int opcode, int offset, int length, Constant cst, int value)1398 public void visitConstant(int opcode, int offset, int length, 1399 Constant cst, int value) { 1400 this.cst = cst; 1401 this.length = length; 1402 this.value = value; 1403 } 1404 1405 /** {@inheritDoc} */ 1406 @Override visitBranch(int opcode, int offset, int length, int target)1407 public void visitBranch(int opcode, int offset, int length, 1408 int target) { 1409 clear(); 1410 } 1411 1412 /** {@inheritDoc} */ 1413 @Override visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1414 public void visitSwitch(int opcode, int offset, int length, 1415 SwitchList cases, int padding) { 1416 clear(); 1417 } 1418 1419 /** {@inheritDoc} */ 1420 @Override visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1421 public void visitNewarray(int offset, int length, CstType type, 1422 ArrayList<Constant> initVals) { 1423 clear(); 1424 } 1425 1426 /** {@inheritDoc} */ 1427 @Override setPreviousOffset(int offset)1428 public void setPreviousOffset(int offset) { 1429 // Intentionally left empty 1430 } 1431 1432 /** {@inheritDoc} */ 1433 @Override getPreviousOffset()1434 public int getPreviousOffset() { 1435 // Intentionally left empty 1436 return -1; 1437 } 1438 } 1439 } 1440