1 /* 2 * Copyright (C) 2011 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.io.instructions; 18 19 import com.android.dex.DexException; 20 import com.android.dx.io.IndexType; 21 import com.android.dx.io.OpcodeInfo; 22 import com.android.dx.io.Opcodes; 23 import com.android.dx.util.Hex; 24 import java.io.EOFException; 25 import java.util.Arrays; 26 27 /** 28 * Representation of an instruction format, which knows how to decode into 29 * and encode from instances of {@link DecodedInstruction}. 30 */ 31 public enum InstructionCodec { FORMAT_00X()32 FORMAT_00X() { 33 @Override 34 public DecodedInstruction decode(int opcodeUnit, 35 CodeInput in) throws EOFException { 36 return new ZeroRegisterDecodedInstruction( 37 this, opcodeUnit, 0, null, 38 0, 0L); 39 } 40 41 @Override 42 public void encode(DecodedInstruction insn, CodeOutput out) { 43 out.write(insn.getOpcodeUnit()); 44 } 45 }, 46 FORMAT_10X()47 FORMAT_10X() { 48 @Override 49 public DecodedInstruction decode(int opcodeUnit, 50 CodeInput in) throws EOFException { 51 int opcode = byte0(opcodeUnit); 52 int literal = byte1(opcodeUnit); // should be zero 53 return new ZeroRegisterDecodedInstruction( 54 this, opcode, 0, null, 55 0, literal); 56 } 57 58 @Override 59 public void encode(DecodedInstruction insn, CodeOutput out) { 60 out.write(insn.getOpcodeUnit()); 61 } 62 }, 63 FORMAT_12X()64 FORMAT_12X() { 65 @Override 66 public DecodedInstruction decode(int opcodeUnit, 67 CodeInput in) throws EOFException { 68 int opcode = byte0(opcodeUnit); 69 int a = nibble2(opcodeUnit); 70 int b = nibble3(opcodeUnit); 71 return new TwoRegisterDecodedInstruction( 72 this, opcode, 0, null, 73 0, 0L, 74 a, b); 75 } 76 77 @Override 78 public void encode(DecodedInstruction insn, CodeOutput out) { 79 out.write( 80 codeUnit(insn.getOpcodeUnit(), 81 makeByte(insn.getA(), insn.getB()))); 82 } 83 }, 84 FORMAT_11N()85 FORMAT_11N() { 86 @Override 87 public DecodedInstruction decode(int opcodeUnit, 88 CodeInput in) throws EOFException { 89 int opcode = byte0(opcodeUnit); 90 int a = nibble2(opcodeUnit); 91 int literal = (nibble3(opcodeUnit) << 28) >> 28; // sign-extend 92 return new OneRegisterDecodedInstruction( 93 this, opcode, 0, null, 94 0, literal, 95 a); 96 } 97 98 @Override 99 public void encode(DecodedInstruction insn, CodeOutput out) { 100 out.write( 101 codeUnit(insn.getOpcodeUnit(), 102 makeByte(insn.getA(), insn.getLiteralNibble()))); 103 } 104 }, 105 FORMAT_11X()106 FORMAT_11X() { 107 @Override 108 public DecodedInstruction decode(int opcodeUnit, 109 CodeInput in) throws EOFException { 110 int opcode = byte0(opcodeUnit); 111 int a = byte1(opcodeUnit); 112 return new OneRegisterDecodedInstruction( 113 this, opcode, 0, null, 114 0, 0L, 115 a); 116 } 117 118 @Override 119 public void encode(DecodedInstruction insn, CodeOutput out) { 120 out.write(codeUnit(insn.getOpcode(), insn.getA())); 121 } 122 }, 123 FORMAT_10T()124 FORMAT_10T() { 125 @Override 126 public DecodedInstruction decode(int opcodeUnit, 127 CodeInput in) throws EOFException { 128 int baseAddress = in.cursor() - 1; 129 int opcode = byte0(opcodeUnit); 130 int target = (byte) byte1(opcodeUnit); // sign-extend 131 return new ZeroRegisterDecodedInstruction( 132 this, opcode, 0, null, 133 baseAddress + target, 0L); 134 } 135 136 @Override 137 public void encode(DecodedInstruction insn, CodeOutput out) { 138 int relativeTarget = insn.getTargetByte(out.cursor()); 139 out.write(codeUnit(insn.getOpcode(), relativeTarget)); 140 } 141 }, 142 FORMAT_20T()143 FORMAT_20T() { 144 @Override 145 public DecodedInstruction decode(int opcodeUnit, 146 CodeInput in) throws EOFException { 147 int baseAddress = in.cursor() - 1; 148 int opcode = byte0(opcodeUnit); 149 int literal = byte1(opcodeUnit); // should be zero 150 int target = (short) in.read(); // sign-extend 151 return new ZeroRegisterDecodedInstruction( 152 this, opcode, 0, null, 153 baseAddress + target, literal); 154 } 155 156 @Override 157 public void encode(DecodedInstruction insn, CodeOutput out) { 158 short relativeTarget = insn.getTargetUnit(out.cursor()); 159 out.write(insn.getOpcodeUnit(), relativeTarget); 160 } 161 }, 162 FORMAT_20BC()163 FORMAT_20BC() { 164 @Override 165 public DecodedInstruction decode(int opcodeUnit, 166 CodeInput in) throws EOFException { 167 // Note: We use the literal field to hold the decoded AA value. 168 int opcode = byte0(opcodeUnit); 169 int literal = byte1(opcodeUnit); 170 int index = in.read(); 171 return new ZeroRegisterDecodedInstruction( 172 this, opcode, index, IndexType.VARIES, 173 0, literal); 174 } 175 176 @Override 177 public void encode(DecodedInstruction insn, CodeOutput out) { 178 out.write( 179 codeUnit(insn.getOpcode(), insn.getLiteralByte()), 180 insn.getIndexUnit()); 181 } 182 }, 183 FORMAT_22X()184 FORMAT_22X() { 185 @Override 186 public DecodedInstruction decode(int opcodeUnit, 187 CodeInput in) throws EOFException { 188 int opcode = byte0(opcodeUnit); 189 int a = byte1(opcodeUnit); 190 int b = in.read(); 191 return new TwoRegisterDecodedInstruction( 192 this, opcode, 0, null, 193 0, 0L, 194 a, b); 195 } 196 197 @Override 198 public void encode(DecodedInstruction insn, CodeOutput out) { 199 out.write( 200 codeUnit(insn.getOpcode(), insn.getA()), 201 insn.getBUnit()); 202 } 203 }, 204 FORMAT_21T()205 FORMAT_21T() { 206 @Override 207 public DecodedInstruction decode(int opcodeUnit, 208 CodeInput in) throws EOFException { 209 int baseAddress = in.cursor() - 1; 210 int opcode = byte0(opcodeUnit); 211 int a = byte1(opcodeUnit); 212 int target = (short) in.read(); // sign-extend 213 return new OneRegisterDecodedInstruction( 214 this, opcode, 0, null, 215 baseAddress + target, 0L, 216 a); 217 } 218 219 @Override 220 public void encode(DecodedInstruction insn, CodeOutput out) { 221 short relativeTarget = insn.getTargetUnit(out.cursor()); 222 out.write(codeUnit(insn.getOpcode(), insn.getA()), relativeTarget); 223 } 224 }, 225 FORMAT_21S()226 FORMAT_21S() { 227 @Override 228 public DecodedInstruction decode(int opcodeUnit, 229 CodeInput in) throws EOFException { 230 int opcode = byte0(opcodeUnit); 231 int a = byte1(opcodeUnit); 232 int literal = (short) in.read(); // sign-extend 233 return new OneRegisterDecodedInstruction( 234 this, opcode, 0, null, 235 0, literal, 236 a); 237 } 238 239 @Override 240 public void encode(DecodedInstruction insn, CodeOutput out) { 241 out.write( 242 codeUnit(insn.getOpcode(), insn.getA()), 243 insn.getLiteralUnit()); 244 } 245 }, 246 FORMAT_21H()247 FORMAT_21H() { 248 @Override 249 public DecodedInstruction decode(int opcodeUnit, 250 CodeInput in) throws EOFException { 251 int opcode = byte0(opcodeUnit); 252 int a = byte1(opcodeUnit); 253 long literal = (short) in.read(); // sign-extend 254 255 /* 256 * Format 21h decodes differently depending on the opcode, 257 * because the "signed hat" might represent either a 32- 258 * or 64- bit value. 259 */ 260 literal <<= (opcode == Opcodes.CONST_HIGH16) ? 16 : 48; 261 262 return new OneRegisterDecodedInstruction( 263 this, opcode, 0, null, 264 0, literal, 265 a); 266 } 267 268 @Override 269 public void encode(DecodedInstruction insn, CodeOutput out) { 270 // See above. 271 int opcode = insn.getOpcode(); 272 int shift = (opcode == Opcodes.CONST_HIGH16) ? 16 : 48; 273 short literal = (short) (insn.getLiteral() >> shift); 274 275 out.write(codeUnit(opcode, insn.getA()), literal); 276 } 277 }, 278 FORMAT_21C()279 FORMAT_21C() { 280 @Override 281 public DecodedInstruction decode(int opcodeUnit, 282 CodeInput in) throws EOFException { 283 int opcode = byte0(opcodeUnit); 284 int a = byte1(opcodeUnit); 285 int index = in.read(); 286 IndexType indexType = OpcodeInfo.getIndexType(opcode); 287 return new OneRegisterDecodedInstruction( 288 this, opcode, index, indexType, 289 0, 0L, 290 a); 291 } 292 293 @Override 294 public void encode(DecodedInstruction insn, CodeOutput out) { 295 out.write( 296 codeUnit(insn.getOpcode(), insn.getA()), 297 insn.getIndexUnit()); 298 } 299 }, 300 FORMAT_23X()301 FORMAT_23X() { 302 @Override 303 public DecodedInstruction decode(int opcodeUnit, 304 CodeInput in) throws EOFException { 305 int opcode = byte0(opcodeUnit); 306 int a = byte1(opcodeUnit); 307 int bc = in.read(); 308 int b = byte0(bc); 309 int c = byte1(bc); 310 return new ThreeRegisterDecodedInstruction( 311 this, opcode, 0, null, 312 0, 0L, 313 a, b, c); 314 } 315 316 @Override 317 public void encode(DecodedInstruction insn, CodeOutput out) { 318 out.write( 319 codeUnit(insn.getOpcode(), insn.getA()), 320 codeUnit(insn.getB(), insn.getC())); 321 } 322 }, 323 FORMAT_22B()324 FORMAT_22B() { 325 @Override 326 public DecodedInstruction decode(int opcodeUnit, 327 CodeInput in) throws EOFException { 328 int opcode = byte0(opcodeUnit); 329 int a = byte1(opcodeUnit); 330 int bc = in.read(); 331 int b = byte0(bc); 332 int literal = (byte) byte1(bc); // sign-extend 333 return new TwoRegisterDecodedInstruction( 334 this, opcode, 0, null, 335 0, literal, 336 a, b); 337 } 338 339 @Override 340 public void encode(DecodedInstruction insn, CodeOutput out) { 341 out.write( 342 codeUnit(insn.getOpcode(), insn.getA()), 343 codeUnit(insn.getB(), 344 insn.getLiteralByte())); 345 } 346 }, 347 FORMAT_22T()348 FORMAT_22T() { 349 @Override 350 public DecodedInstruction decode(int opcodeUnit, 351 CodeInput in) throws EOFException { 352 int baseAddress = in.cursor() - 1; 353 int opcode = byte0(opcodeUnit); 354 int a = nibble2(opcodeUnit); 355 int b = nibble3(opcodeUnit); 356 int target = (short) in.read(); // sign-extend 357 return new TwoRegisterDecodedInstruction( 358 this, opcode, 0, null, 359 baseAddress + target, 0L, 360 a, b); 361 } 362 363 @Override 364 public void encode(DecodedInstruction insn, CodeOutput out) { 365 short relativeTarget = insn.getTargetUnit(out.cursor()); 366 out.write( 367 codeUnit(insn.getOpcode(), 368 makeByte(insn.getA(), insn.getB())), 369 relativeTarget); 370 } 371 }, 372 FORMAT_22S()373 FORMAT_22S() { 374 @Override 375 public DecodedInstruction decode(int opcodeUnit, 376 CodeInput in) throws EOFException { 377 int opcode = byte0(opcodeUnit); 378 int a = nibble2(opcodeUnit); 379 int b = nibble3(opcodeUnit); 380 int literal = (short) in.read(); // sign-extend 381 return new TwoRegisterDecodedInstruction( 382 this, opcode, 0, null, 383 0, literal, 384 a, b); 385 } 386 387 @Override 388 public void encode(DecodedInstruction insn, CodeOutput out) { 389 out.write( 390 codeUnit(insn.getOpcode(), 391 makeByte(insn.getA(), insn.getB())), 392 insn.getLiteralUnit()); 393 } 394 }, 395 FORMAT_22C()396 FORMAT_22C() { 397 @Override 398 public DecodedInstruction decode(int opcodeUnit, 399 CodeInput in) throws EOFException { 400 int opcode = byte0(opcodeUnit); 401 int a = nibble2(opcodeUnit); 402 int b = nibble3(opcodeUnit); 403 int index = in.read(); 404 IndexType indexType = OpcodeInfo.getIndexType(opcode); 405 return new TwoRegisterDecodedInstruction( 406 this, opcode, index, indexType, 407 0, 0L, 408 a, b); 409 } 410 411 @Override 412 public void encode(DecodedInstruction insn, CodeOutput out) { 413 out.write( 414 codeUnit(insn.getOpcode(), 415 makeByte(insn.getA(), insn.getB())), 416 insn.getIndexUnit()); 417 } 418 }, 419 FORMAT_22CS()420 FORMAT_22CS() { 421 @Override 422 public DecodedInstruction decode(int opcodeUnit, 423 CodeInput in) throws EOFException { 424 int opcode = byte0(opcodeUnit); 425 int a = nibble2(opcodeUnit); 426 int b = nibble3(opcodeUnit); 427 int index = in.read(); 428 return new TwoRegisterDecodedInstruction( 429 this, opcode, index, IndexType.FIELD_OFFSET, 430 0, 0L, 431 a, b); 432 } 433 434 @Override 435 public void encode(DecodedInstruction insn, CodeOutput out) { 436 out.write( 437 codeUnit(insn.getOpcode(), 438 makeByte(insn.getA(), insn.getB())), 439 insn.getIndexUnit()); 440 } 441 }, 442 FORMAT_30T()443 FORMAT_30T() { 444 @Override 445 public DecodedInstruction decode(int opcodeUnit, 446 CodeInput in) throws EOFException { 447 int baseAddress = in.cursor() - 1; 448 int opcode = byte0(opcodeUnit); 449 int literal = byte1(opcodeUnit); // should be zero 450 int target = in.readInt(); 451 return new ZeroRegisterDecodedInstruction( 452 this, opcode, 0, null, 453 baseAddress + target, literal); 454 } 455 456 @Override 457 public void encode(DecodedInstruction insn, CodeOutput out) { 458 int relativeTarget = insn.getTarget(out.cursor()); 459 out.write(insn.getOpcodeUnit(), 460 unit0(relativeTarget), unit1(relativeTarget)); 461 } 462 }, 463 FORMAT_32X()464 FORMAT_32X() { 465 @Override 466 public DecodedInstruction decode(int opcodeUnit, 467 CodeInput in) throws EOFException { 468 int opcode = byte0(opcodeUnit); 469 int literal = byte1(opcodeUnit); // should be zero 470 int a = in.read(); 471 int b = in.read(); 472 return new TwoRegisterDecodedInstruction( 473 this, opcode, 0, null, 474 0, literal, 475 a, b); 476 } 477 478 @Override 479 public void encode(DecodedInstruction insn, CodeOutput out) { 480 out.write(insn.getOpcodeUnit(), insn.getAUnit(), insn.getBUnit()); 481 } 482 }, 483 FORMAT_31I()484 FORMAT_31I() { 485 @Override 486 public DecodedInstruction decode(int opcodeUnit, 487 CodeInput in) throws EOFException { 488 int opcode = byte0(opcodeUnit); 489 int a = byte1(opcodeUnit); 490 int literal = in.readInt(); 491 return new OneRegisterDecodedInstruction( 492 this, opcode, 0, null, 493 0, literal, 494 a); 495 } 496 497 @Override 498 public void encode(DecodedInstruction insn, CodeOutput out) { 499 int literal = insn.getLiteralInt(); 500 out.write( 501 codeUnit(insn.getOpcode(), insn.getA()), 502 unit0(literal), 503 unit1(literal)); 504 } 505 }, 506 FORMAT_31T()507 FORMAT_31T() { 508 @Override 509 public DecodedInstruction decode(int opcodeUnit, 510 CodeInput in) throws EOFException { 511 int baseAddress = in.cursor() - 1; 512 int opcode = byte0(opcodeUnit); 513 int a = byte1(opcodeUnit); 514 int target = baseAddress + in.readInt(); 515 516 /* 517 * Switch instructions need to "forward" their addresses to their 518 * payload target instructions. 519 */ 520 switch (opcode) { 521 case Opcodes.PACKED_SWITCH: 522 case Opcodes.SPARSE_SWITCH: { 523 in.setBaseAddress(target, baseAddress); 524 break; 525 } 526 default: // fall out 527 } 528 529 return new OneRegisterDecodedInstruction( 530 this, opcode, 0, null, 531 target, 0L, 532 a); 533 } 534 535 @Override 536 public void encode(DecodedInstruction insn, CodeOutput out) { 537 int relativeTarget = insn.getTarget(out.cursor()); 538 out.write( 539 codeUnit(insn.getOpcode(), insn.getA()), 540 unit0(relativeTarget), unit1(relativeTarget)); 541 } 542 }, 543 FORMAT_31C()544 FORMAT_31C() { 545 @Override 546 public DecodedInstruction decode(int opcodeUnit, 547 CodeInput in) throws EOFException { 548 int opcode = byte0(opcodeUnit); 549 int a = byte1(opcodeUnit); 550 int index = in.readInt(); 551 IndexType indexType = OpcodeInfo.getIndexType(opcode); 552 return new OneRegisterDecodedInstruction( 553 this, opcode, index, indexType, 554 0, 0L, 555 a); 556 } 557 558 @Override 559 public void encode(DecodedInstruction insn, CodeOutput out) { 560 int index = insn.getIndex(); 561 out.write( 562 codeUnit(insn.getOpcode(), insn.getA()), 563 unit0(index), 564 unit1(index)); 565 } 566 }, 567 FORMAT_35C()568 FORMAT_35C() { 569 @Override 570 public DecodedInstruction decode(int opcodeUnit, 571 CodeInput in) throws EOFException { 572 return decodeRegisterList(this, opcodeUnit, in); 573 } 574 575 @Override 576 public void encode(DecodedInstruction insn, CodeOutput out) { 577 encodeRegisterList(insn, out); 578 } 579 }, 580 FORMAT_35MS()581 FORMAT_35MS() { 582 @Override 583 public DecodedInstruction decode(int opcodeUnit, 584 CodeInput in) throws EOFException { 585 return decodeRegisterList(this, opcodeUnit, in); 586 } 587 588 @Override 589 public void encode(DecodedInstruction insn, CodeOutput out) { 590 encodeRegisterList(insn, out); 591 } 592 }, 593 FORMAT_35MI()594 FORMAT_35MI() { 595 @Override 596 public DecodedInstruction decode(int opcodeUnit, 597 CodeInput in) throws EOFException { 598 return decodeRegisterList(this, opcodeUnit, in); 599 } 600 601 @Override 602 public void encode(DecodedInstruction insn, CodeOutput out) { 603 encodeRegisterList(insn, out); 604 } 605 }, 606 FORMAT_3RC()607 FORMAT_3RC() { 608 @Override 609 public DecodedInstruction decode(int opcodeUnit, 610 CodeInput in) throws EOFException { 611 return decodeRegisterRange(this, opcodeUnit, in); 612 } 613 614 @Override 615 public void encode(DecodedInstruction insn, CodeOutput out) { 616 encodeRegisterRange(insn, out); 617 } 618 }, 619 FORMAT_3RMS()620 FORMAT_3RMS() { 621 @Override 622 public DecodedInstruction decode(int opcodeUnit, 623 CodeInput in) throws EOFException { 624 return decodeRegisterRange(this, opcodeUnit, in); 625 } 626 627 @Override 628 public void encode(DecodedInstruction insn, CodeOutput out) { 629 encodeRegisterRange(insn, out); 630 } 631 }, 632 FORMAT_3RMI()633 FORMAT_3RMI() { 634 @Override 635 public DecodedInstruction decode(int opcodeUnit, 636 CodeInput in) throws EOFException { 637 return decodeRegisterRange(this, opcodeUnit, in); 638 } 639 640 @Override 641 public void encode(DecodedInstruction insn, CodeOutput out) { 642 encodeRegisterRange(insn, out); 643 } 644 }, 645 FORMAT_51L()646 FORMAT_51L() { 647 @Override 648 public DecodedInstruction decode(int opcodeUnit, 649 CodeInput in) throws EOFException { 650 int opcode = byte0(opcodeUnit); 651 int a = byte1(opcodeUnit); 652 long literal = in.readLong(); 653 return new OneRegisterDecodedInstruction( 654 this, opcode, 0, null, 655 0, literal, 656 a); 657 } 658 659 @Override 660 public void encode(DecodedInstruction insn, CodeOutput out) { 661 long literal = insn.getLiteral(); 662 out.write( 663 codeUnit(insn.getOpcode(), insn.getA()), 664 unit0(literal), 665 unit1(literal), 666 unit2(literal), 667 unit3(literal)); 668 } 669 }, 670 FORMAT_45CC()671 FORMAT_45CC() { 672 @Override 673 public DecodedInstruction decode(int opcodeUnit, 674 CodeInput in) throws EOFException { 675 int opcode = byte0(opcodeUnit); 676 if (opcode != Opcodes.INVOKE_POLYMORPHIC) { 677 // 45cc isn't currently used for anything other than invoke-polymorphic. 678 // If that changes, add a more general DecodedInstruction for this format. 679 throw new UnsupportedOperationException(String.valueOf(opcode)); 680 } 681 int g = nibble2(opcodeUnit); 682 int registerCount = nibble3(opcodeUnit); 683 int methodIndex = in.read(); 684 int cdef = in.read(); 685 int c = nibble0(cdef); 686 int d = nibble1(cdef); 687 int e = nibble2(cdef); 688 int f = nibble3(cdef); 689 int protoIndex = in.read(); 690 IndexType indexType = OpcodeInfo.getIndexType(opcode); 691 692 if (registerCount < 1 || registerCount > 5) { 693 throw new DexException("bogus registerCount: " + Hex.uNibble(registerCount)); 694 } 695 int[] registers = {c, d, e, f, g}; 696 registers = Arrays.copyOfRange(registers, 0, registerCount); 697 698 return new InvokePolymorphicDecodedInstruction( 699 this, opcode, methodIndex, indexType, protoIndex, registers); 700 } 701 702 @Override 703 public void encode(DecodedInstruction insn, CodeOutput out) { 704 InvokePolymorphicDecodedInstruction polyInsn = 705 (InvokePolymorphicDecodedInstruction) insn; 706 out.write(codeUnit(polyInsn.getOpcode(), 707 makeByte(polyInsn.getG(), polyInsn.getRegisterCount())), 708 polyInsn.getIndexUnit(), 709 codeUnit(polyInsn.getC(), polyInsn.getD(), polyInsn.getE(), polyInsn.getF()), 710 polyInsn.getProtoIndex()); 711 712 } 713 }, 714 FORMAT_4RCC()715 FORMAT_4RCC() { 716 @Override 717 public DecodedInstruction decode(int opcodeUnit, 718 CodeInput in) throws EOFException { 719 int opcode = byte0(opcodeUnit); 720 if (opcode != Opcodes.INVOKE_POLYMORPHIC_RANGE) { 721 // 4rcc isn't currently used for anything other than invoke-polymorphic. 722 // If that changes, add a more general DecodedInstruction for this format. 723 throw new UnsupportedOperationException(String.valueOf(opcode)); 724 } 725 int registerCount = byte1(opcodeUnit); 726 int methodIndex = in.read(); 727 int c = in.read(); 728 int protoIndex = in.read(); 729 IndexType indexType = OpcodeInfo.getIndexType(opcode); 730 return new InvokePolymorphicRangeDecodedInstruction( 731 this, opcode, methodIndex, indexType, c, registerCount, protoIndex); 732 733 } 734 735 @Override 736 public void encode(DecodedInstruction insn, CodeOutput out) { 737 out.write( 738 codeUnit(insn.getOpcode(), insn.getRegisterCount()), 739 insn.getIndexUnit(), 740 insn.getCUnit(), 741 insn.getProtoIndex()); 742 743 } 744 }, 745 FORMAT_PACKED_SWITCH_PAYLOAD()746 FORMAT_PACKED_SWITCH_PAYLOAD() { 747 @Override 748 public DecodedInstruction decode(int opcodeUnit, 749 CodeInput in) throws EOFException { 750 int baseAddress = in.baseAddressForCursor() - 1; // already read opcode 751 int size = in.read(); 752 int firstKey = in.readInt(); 753 int[] targets = new int[size]; 754 755 for (int i = 0; i < size; i++) { 756 targets[i] = baseAddress + in.readInt(); 757 } 758 759 return new PackedSwitchPayloadDecodedInstruction( 760 this, opcodeUnit, firstKey, targets); 761 } 762 763 @Override 764 public void encode(DecodedInstruction insn, CodeOutput out) { 765 PackedSwitchPayloadDecodedInstruction payload = 766 (PackedSwitchPayloadDecodedInstruction) insn; 767 int[] targets = payload.getTargets(); 768 int baseAddress = out.baseAddressForCursor(); 769 770 out.write(payload.getOpcodeUnit()); 771 out.write(asUnsignedUnit(targets.length)); 772 out.writeInt(payload.getFirstKey()); 773 774 for (int target : targets) { 775 out.writeInt(target - baseAddress); 776 } 777 } 778 }, 779 FORMAT_SPARSE_SWITCH_PAYLOAD()780 FORMAT_SPARSE_SWITCH_PAYLOAD() { 781 @Override 782 public DecodedInstruction decode(int opcodeUnit, 783 CodeInput in) throws EOFException { 784 int baseAddress = in.baseAddressForCursor() - 1; // already read opcode 785 int size = in.read(); 786 int[] keys = new int[size]; 787 int[] targets = new int[size]; 788 789 for (int i = 0; i < size; i++) { 790 keys[i] = in.readInt(); 791 } 792 793 for (int i = 0; i < size; i++) { 794 targets[i] = baseAddress + in.readInt(); 795 } 796 797 return new SparseSwitchPayloadDecodedInstruction( 798 this, opcodeUnit, keys, targets); 799 } 800 801 @Override 802 public void encode(DecodedInstruction insn, CodeOutput out) { 803 SparseSwitchPayloadDecodedInstruction payload = 804 (SparseSwitchPayloadDecodedInstruction) insn; 805 int[] keys = payload.getKeys(); 806 int[] targets = payload.getTargets(); 807 int baseAddress = out.baseAddressForCursor(); 808 809 out.write(payload.getOpcodeUnit()); 810 out.write(asUnsignedUnit(targets.length)); 811 812 for (int key : keys) { 813 out.writeInt(key); 814 } 815 816 for (int target : targets) { 817 out.writeInt(target - baseAddress); 818 } 819 } 820 }, 821 FORMAT_FILL_ARRAY_DATA_PAYLOAD()822 FORMAT_FILL_ARRAY_DATA_PAYLOAD() { 823 @Override 824 public DecodedInstruction decode(int opcodeUnit, 825 CodeInput in) throws EOFException { 826 int elementWidth = in.read(); 827 int size = in.readInt(); 828 829 switch (elementWidth) { 830 case 1: { 831 byte[] array = new byte[size]; 832 boolean even = true; 833 for (int i = 0, value = 0; i < size; i++, even = !even) { 834 if (even) { 835 value = in.read(); 836 } 837 array[i] = (byte) (value & 0xff); 838 value >>= 8; 839 } 840 return new FillArrayDataPayloadDecodedInstruction( 841 this, opcodeUnit, array); 842 } 843 case 2: { 844 short[] array = new short[size]; 845 for (int i = 0; i < size; i++) { 846 array[i] = (short) in.read(); 847 } 848 return new FillArrayDataPayloadDecodedInstruction( 849 this, opcodeUnit, array); 850 } 851 case 4: { 852 int[] array = new int[size]; 853 for (int i = 0; i < size; i++) { 854 array[i] = in.readInt(); 855 } 856 return new FillArrayDataPayloadDecodedInstruction( 857 this, opcodeUnit, array); 858 } 859 case 8: { 860 long[] array = new long[size]; 861 for (int i = 0; i < size; i++) { 862 array[i] = in.readLong(); 863 } 864 return new FillArrayDataPayloadDecodedInstruction( 865 this, opcodeUnit, array); 866 } 867 default: // fall out 868 } 869 870 throw new DexException("bogus element_width: " 871 + Hex.u2(elementWidth)); 872 } 873 874 @Override 875 public void encode(DecodedInstruction insn, CodeOutput out) { 876 FillArrayDataPayloadDecodedInstruction payload = 877 (FillArrayDataPayloadDecodedInstruction) insn; 878 short elementWidth = payload.getElementWidthUnit(); 879 Object data = payload.getData(); 880 881 out.write(payload.getOpcodeUnit()); 882 out.write(elementWidth); 883 out.writeInt(payload.getSize()); 884 885 switch (elementWidth) { 886 case 1: out.write((byte[]) data); break; 887 case 2: out.write((short[]) data); break; 888 case 4: out.write((int[]) data); break; 889 case 8: out.write((long[]) data); break; 890 default: { 891 throw new DexException("bogus element_width: " 892 + Hex.u2(elementWidth)); 893 } 894 } 895 } 896 }; 897 898 /** 899 * Decodes an instruction specified by the given opcode unit, reading 900 * any required additional code units from the given input source. 901 */ decode(int opcodeUnit, CodeInput in)902 public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in) 903 throws EOFException; 904 905 /** 906 * Encodes the given instruction. 907 */ encode(DecodedInstruction insn, CodeOutput out)908 public abstract void encode(DecodedInstruction insn, CodeOutput out); 909 910 /** 911 * Helper method that decodes any of the register-list formats. 912 */ decodeRegisterList( InstructionCodec format, int opcodeUnit, CodeInput in)913 private static DecodedInstruction decodeRegisterList( 914 InstructionCodec format, int opcodeUnit, CodeInput in) 915 throws EOFException { 916 int opcode = byte0(opcodeUnit); 917 int e = nibble2(opcodeUnit); 918 int registerCount = nibble3(opcodeUnit); 919 int index = in.read(); 920 int abcd = in.read(); 921 int a = nibble0(abcd); 922 int b = nibble1(abcd); 923 int c = nibble2(abcd); 924 int d = nibble3(abcd); 925 IndexType indexType = OpcodeInfo.getIndexType(opcode); 926 927 // TODO: Having to switch like this is less than ideal. 928 switch (registerCount) { 929 case 0: 930 return new ZeroRegisterDecodedInstruction( 931 format, opcode, index, indexType, 932 0, 0L); 933 case 1: 934 return new OneRegisterDecodedInstruction( 935 format, opcode, index, indexType, 936 0, 0L, 937 a); 938 case 2: 939 return new TwoRegisterDecodedInstruction( 940 format, opcode, index, indexType, 941 0, 0L, 942 a, b); 943 case 3: 944 return new ThreeRegisterDecodedInstruction( 945 format, opcode, index, indexType, 946 0, 0L, 947 a, b, c); 948 case 4: 949 return new FourRegisterDecodedInstruction( 950 format, opcode, index, indexType, 951 0, 0L, 952 a, b, c, d); 953 case 5: 954 return new FiveRegisterDecodedInstruction( 955 format, opcode, index, indexType, 956 0, 0L, 957 a, b, c, d, e); 958 default: // fall out 959 } 960 961 throw new DexException("bogus registerCount: " 962 + Hex.uNibble(registerCount)); 963 } 964 965 /** 966 * Helper method that encodes any of the register-list formats. 967 */ encodeRegisterList(DecodedInstruction insn, CodeOutput out)968 private static void encodeRegisterList(DecodedInstruction insn, 969 CodeOutput out) { 970 out.write(codeUnit(insn.getOpcode(), 971 makeByte(insn.getE(), insn.getRegisterCount())), 972 insn.getIndexUnit(), 973 codeUnit(insn.getA(), insn.getB(), insn.getC(), insn.getD())); 974 } 975 976 /** 977 * Helper method that decodes any of the three-unit register-range formats. 978 */ decodeRegisterRange( InstructionCodec format, int opcodeUnit, CodeInput in)979 private static DecodedInstruction decodeRegisterRange( 980 InstructionCodec format, int opcodeUnit, CodeInput in) 981 throws EOFException { 982 int opcode = byte0(opcodeUnit); 983 int registerCount = byte1(opcodeUnit); 984 int index = in.read(); 985 int a = in.read(); 986 IndexType indexType = OpcodeInfo.getIndexType(opcode); 987 return new RegisterRangeDecodedInstruction( 988 format, opcode, index, indexType, 989 0, 0L, 990 a, registerCount); 991 } 992 993 /** 994 * Helper method that encodes any of the three-unit register-range formats. 995 */ encodeRegisterRange(DecodedInstruction insn, CodeOutput out)996 private static void encodeRegisterRange(DecodedInstruction insn, 997 CodeOutput out) { 998 out.write(codeUnit(insn.getOpcode(), insn.getRegisterCount()), 999 insn.getIndexUnit(), 1000 insn.getAUnit()); 1001 } 1002 codeUnit(int lowByte, int highByte)1003 private static short codeUnit(int lowByte, int highByte) { 1004 if ((lowByte & ~0xff) != 0) { 1005 throw new IllegalArgumentException("bogus lowByte"); 1006 } 1007 1008 if ((highByte & ~0xff) != 0) { 1009 throw new IllegalArgumentException("bogus highByte"); 1010 } 1011 1012 return (short) (lowByte | (highByte << 8)); 1013 } 1014 codeUnit(int nibble0, int nibble1, int nibble2, int nibble3)1015 private static short codeUnit(int nibble0, int nibble1, int nibble2, 1016 int nibble3) { 1017 if ((nibble0 & ~0xf) != 0) { 1018 throw new IllegalArgumentException("bogus nibble0"); 1019 } 1020 1021 if ((nibble1 & ~0xf) != 0) { 1022 throw new IllegalArgumentException("bogus nibble1"); 1023 } 1024 1025 if ((nibble2 & ~0xf) != 0) { 1026 throw new IllegalArgumentException("bogus nibble2"); 1027 } 1028 1029 if ((nibble3 & ~0xf) != 0) { 1030 throw new IllegalArgumentException("bogus nibble3"); 1031 } 1032 1033 return (short) (nibble0 | (nibble1 << 4) 1034 | (nibble2 << 8) | (nibble3 << 12)); 1035 } 1036 makeByte(int lowNibble, int highNibble)1037 private static int makeByte(int lowNibble, int highNibble) { 1038 if ((lowNibble & ~0xf) != 0) { 1039 throw new IllegalArgumentException("bogus lowNibble"); 1040 } 1041 1042 if ((highNibble & ~0xf) != 0) { 1043 throw new IllegalArgumentException("bogus highNibble"); 1044 } 1045 1046 return lowNibble | (highNibble << 4); 1047 } 1048 asUnsignedUnit(int value)1049 private static short asUnsignedUnit(int value) { 1050 if ((value & ~0xffff) != 0) { 1051 throw new IllegalArgumentException("bogus unsigned code unit"); 1052 } 1053 1054 return (short) value; 1055 } 1056 unit0(int value)1057 private static short unit0(int value) { 1058 return (short) value; 1059 } 1060 unit1(int value)1061 private static short unit1(int value) { 1062 return (short) (value >> 16); 1063 } 1064 unit0(long value)1065 private static short unit0(long value) { 1066 return (short) value; 1067 } 1068 unit1(long value)1069 private static short unit1(long value) { 1070 return (short) (value >> 16); 1071 } 1072 unit2(long value)1073 private static short unit2(long value) { 1074 return (short) (value >> 32); 1075 } 1076 unit3(long value)1077 private static short unit3(long value) { 1078 return (short) (value >> 48); 1079 } 1080 byte0(int value)1081 private static int byte0(int value) { 1082 return value & 0xff; 1083 } 1084 byte1(int value)1085 private static int byte1(int value) { 1086 return (value >> 8) & 0xff; 1087 } 1088 byte2(int value)1089 private static int byte2(int value) { 1090 return (value >> 16) & 0xff; 1091 } 1092 byte3(int value)1093 private static int byte3(int value) { 1094 return value >>> 24; 1095 } 1096 nibble0(int value)1097 private static int nibble0(int value) { 1098 return value & 0xf; 1099 } 1100 nibble1(int value)1101 private static int nibble1(int value) { 1102 return (value >> 4) & 0xf; 1103 } 1104 nibble2(int value)1105 private static int nibble2(int value) { 1106 return (value >> 8) & 0xf; 1107 } 1108 nibble3(int value)1109 private static int nibble3(int value) { 1110 return (value >> 12) & 0xf; 1111 } 1112 } 1113