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