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