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