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