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_PACKED_SWITCH_PAYLOAD()607 FORMAT_PACKED_SWITCH_PAYLOAD() { 608 @Override public DecodedInstruction decode(int opcodeUnit, 609 CodeInput in) throws EOFException { 610 int baseAddress = in.baseAddressForCursor() - 1; // already read opcode 611 int size = in.read(); 612 int firstKey = in.readInt(); 613 int[] targets = new int[size]; 614 615 for (int i = 0; i < size; i++) { 616 targets[i] = baseAddress + in.readInt(); 617 } 618 619 return new PackedSwitchPayloadDecodedInstruction( 620 this, opcodeUnit, firstKey, targets); 621 } 622 623 @Override public void encode(DecodedInstruction insn, CodeOutput out) { 624 PackedSwitchPayloadDecodedInstruction payload = 625 (PackedSwitchPayloadDecodedInstruction) insn; 626 int[] targets = payload.getTargets(); 627 int baseAddress = out.baseAddressForCursor(); 628 629 out.write(payload.getOpcodeUnit()); 630 out.write(asUnsignedUnit(targets.length)); 631 out.writeInt(payload.getFirstKey()); 632 633 for (int target : targets) { 634 out.writeInt(target - baseAddress); 635 } 636 } 637 }, 638 FORMAT_SPARSE_SWITCH_PAYLOAD()639 FORMAT_SPARSE_SWITCH_PAYLOAD() { 640 @Override public DecodedInstruction decode(int opcodeUnit, 641 CodeInput in) throws EOFException { 642 int baseAddress = in.baseAddressForCursor() - 1; // already read opcode 643 int size = in.read(); 644 int[] keys = new int[size]; 645 int[] targets = new int[size]; 646 647 for (int i = 0; i < size; i++) { 648 keys[i] = in.readInt(); 649 } 650 651 for (int i = 0; i < size; i++) { 652 targets[i] = baseAddress + in.readInt(); 653 } 654 655 return new SparseSwitchPayloadDecodedInstruction( 656 this, opcodeUnit, keys, targets); 657 } 658 659 @Override public void encode(DecodedInstruction insn, CodeOutput out) { 660 SparseSwitchPayloadDecodedInstruction payload = 661 (SparseSwitchPayloadDecodedInstruction) insn; 662 int[] keys = payload.getKeys(); 663 int[] targets = payload.getTargets(); 664 int baseAddress = out.baseAddressForCursor(); 665 666 out.write(payload.getOpcodeUnit()); 667 out.write(asUnsignedUnit(targets.length)); 668 669 for (int key : keys) { 670 out.writeInt(key); 671 } 672 673 for (int target : targets) { 674 out.writeInt(target - baseAddress); 675 } 676 } 677 }, 678 FORMAT_FILL_ARRAY_DATA_PAYLOAD()679 FORMAT_FILL_ARRAY_DATA_PAYLOAD() { 680 @Override public DecodedInstruction decode(int opcodeUnit, 681 CodeInput in) throws EOFException { 682 int elementWidth = in.read(); 683 int size = in.readInt(); 684 685 switch (elementWidth) { 686 case 1: { 687 byte[] array = new byte[size]; 688 boolean even = true; 689 for (int i = 0, value = 0; i < size; i++, even = !even) { 690 if (even) { 691 value = in.read(); 692 } 693 array[i] = (byte) (value & 0xff); 694 value >>= 8; 695 } 696 return new FillArrayDataPayloadDecodedInstruction( 697 this, opcodeUnit, array); 698 } 699 case 2: { 700 short[] array = new short[size]; 701 for (int i = 0; i < size; i++) { 702 array[i] = (short) in.read(); 703 } 704 return new FillArrayDataPayloadDecodedInstruction( 705 this, opcodeUnit, array); 706 } 707 case 4: { 708 int[] array = new int[size]; 709 for (int i = 0; i < size; i++) { 710 array[i] = in.readInt(); 711 } 712 return new FillArrayDataPayloadDecodedInstruction( 713 this, opcodeUnit, array); 714 } 715 case 8: { 716 long[] array = new long[size]; 717 for (int i = 0; i < size; i++) { 718 array[i] = in.readLong(); 719 } 720 return new FillArrayDataPayloadDecodedInstruction( 721 this, opcodeUnit, array); 722 } 723 } 724 725 throw new DexException("bogus element_width: " 726 + Hex.u2(elementWidth)); 727 } 728 729 @Override public void encode(DecodedInstruction insn, CodeOutput out) { 730 FillArrayDataPayloadDecodedInstruction payload = 731 (FillArrayDataPayloadDecodedInstruction) insn; 732 short elementWidth = payload.getElementWidthUnit(); 733 Object data = payload.getData(); 734 735 out.write(payload.getOpcodeUnit()); 736 out.write(elementWidth); 737 out.writeInt(payload.getSize()); 738 739 switch (elementWidth) { 740 case 1: out.write((byte[]) data); break; 741 case 2: out.write((short[]) data); break; 742 case 4: out.write((int[]) data); break; 743 case 8: out.write((long[]) data); break; 744 default: { 745 throw new DexException("bogus element_width: " 746 + Hex.u2(elementWidth)); 747 } 748 } 749 } 750 }; 751 752 /** 753 * Decodes an instruction specified by the given opcode unit, reading 754 * any required additional code units from the given input source. 755 */ decode(int opcodeUnit, CodeInput in)756 public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in) 757 throws EOFException; 758 759 /** 760 * Encodes the given instruction. 761 */ encode(DecodedInstruction insn, CodeOutput out)762 public abstract void encode(DecodedInstruction insn, CodeOutput out); 763 764 /** 765 * Helper method that decodes any of the register-list formats. 766 */ decodeRegisterList( InstructionCodec format, int opcodeUnit, CodeInput in)767 private static DecodedInstruction decodeRegisterList( 768 InstructionCodec format, int opcodeUnit, CodeInput in) 769 throws EOFException { 770 int opcode = byte0(opcodeUnit); 771 int e = nibble2(opcodeUnit); 772 int registerCount = nibble3(opcodeUnit); 773 int index = in.read(); 774 int abcd = in.read(); 775 int a = nibble0(abcd); 776 int b = nibble1(abcd); 777 int c = nibble2(abcd); 778 int d = nibble3(abcd); 779 IndexType indexType = OpcodeInfo.getIndexType(opcode); 780 781 // TODO: Having to switch like this is less than ideal. 782 switch (registerCount) { 783 case 0: 784 return new ZeroRegisterDecodedInstruction( 785 format, opcode, index, indexType, 786 0, 0L); 787 case 1: 788 return new OneRegisterDecodedInstruction( 789 format, opcode, index, indexType, 790 0, 0L, 791 a); 792 case 2: 793 return new TwoRegisterDecodedInstruction( 794 format, opcode, index, indexType, 795 0, 0L, 796 a, b); 797 case 3: 798 return new ThreeRegisterDecodedInstruction( 799 format, opcode, index, indexType, 800 0, 0L, 801 a, b, c); 802 case 4: 803 return new FourRegisterDecodedInstruction( 804 format, opcode, index, indexType, 805 0, 0L, 806 a, b, c, d); 807 case 5: 808 return new FiveRegisterDecodedInstruction( 809 format, opcode, index, indexType, 810 0, 0L, 811 a, b, c, d, e); 812 } 813 814 throw new DexException("bogus registerCount: " 815 + Hex.uNibble(registerCount)); 816 } 817 818 /** 819 * Helper method that encodes any of the register-list formats. 820 */ encodeRegisterList(DecodedInstruction insn, CodeOutput out)821 private static void encodeRegisterList(DecodedInstruction insn, 822 CodeOutput out) { 823 out.write(codeUnit(insn.getOpcode(), 824 makeByte(insn.getE(), insn.getRegisterCount())), 825 insn.getIndexUnit(), 826 codeUnit(insn.getA(), insn.getB(), insn.getC(), insn.getD())); 827 } 828 829 /** 830 * Helper method that decodes any of the three-unit register-range formats. 831 */ decodeRegisterRange( InstructionCodec format, int opcodeUnit, CodeInput in)832 private static DecodedInstruction decodeRegisterRange( 833 InstructionCodec format, int opcodeUnit, CodeInput in) 834 throws EOFException { 835 int opcode = byte0(opcodeUnit); 836 int registerCount = byte1(opcodeUnit); 837 int index = in.read(); 838 int a = in.read(); 839 IndexType indexType = OpcodeInfo.getIndexType(opcode); 840 return new RegisterRangeDecodedInstruction( 841 format, opcode, index, indexType, 842 0, 0L, 843 a, registerCount); 844 } 845 846 /** 847 * Helper method that encodes any of the three-unit register-range formats. 848 */ encodeRegisterRange(DecodedInstruction insn, CodeOutput out)849 private static void encodeRegisterRange(DecodedInstruction insn, 850 CodeOutput out) { 851 out.write(codeUnit(insn.getOpcode(), insn.getRegisterCount()), 852 insn.getIndexUnit(), 853 insn.getAUnit()); 854 } 855 codeUnit(int lowByte, int highByte)856 private static short codeUnit(int lowByte, int highByte) { 857 if ((lowByte & ~0xff) != 0) { 858 throw new IllegalArgumentException("bogus lowByte"); 859 } 860 861 if ((highByte & ~0xff) != 0) { 862 throw new IllegalArgumentException("bogus highByte"); 863 } 864 865 return (short) (lowByte | (highByte << 8)); 866 } 867 codeUnit(int nibble0, int nibble1, int nibble2, int nibble3)868 private static short codeUnit(int nibble0, int nibble1, int nibble2, 869 int nibble3) { 870 if ((nibble0 & ~0xf) != 0) { 871 throw new IllegalArgumentException("bogus nibble0"); 872 } 873 874 if ((nibble1 & ~0xf) != 0) { 875 throw new IllegalArgumentException("bogus nibble1"); 876 } 877 878 if ((nibble2 & ~0xf) != 0) { 879 throw new IllegalArgumentException("bogus nibble2"); 880 } 881 882 if ((nibble3 & ~0xf) != 0) { 883 throw new IllegalArgumentException("bogus nibble3"); 884 } 885 886 return (short) (nibble0 | (nibble1 << 4) 887 | (nibble2 << 8) | (nibble3 << 12)); 888 } 889 makeByte(int lowNibble, int highNibble)890 private static int makeByte(int lowNibble, int highNibble) { 891 if ((lowNibble & ~0xf) != 0) { 892 throw new IllegalArgumentException("bogus lowNibble"); 893 } 894 895 if ((highNibble & ~0xf) != 0) { 896 throw new IllegalArgumentException("bogus highNibble"); 897 } 898 899 return lowNibble | (highNibble << 4); 900 } 901 asUnsignedUnit(int value)902 private static short asUnsignedUnit(int value) { 903 if ((value & ~0xffff) != 0) { 904 throw new IllegalArgumentException("bogus unsigned code unit"); 905 } 906 907 return (short) value; 908 } 909 unit0(int value)910 private static short unit0(int value) { 911 return (short) value; 912 } 913 unit1(int value)914 private static short unit1(int value) { 915 return (short) (value >> 16); 916 } 917 unit0(long value)918 private static short unit0(long value) { 919 return (short) value; 920 } 921 unit1(long value)922 private static short unit1(long value) { 923 return (short) (value >> 16); 924 } 925 unit2(long value)926 private static short unit2(long value) { 927 return (short) (value >> 32); 928 } 929 unit3(long value)930 private static short unit3(long value) { 931 return (short) (value >> 48); 932 } 933 byte0(int value)934 private static int byte0(int value) { 935 return value & 0xff; 936 } 937 byte1(int value)938 private static int byte1(int value) { 939 return (value >> 8) & 0xff; 940 } 941 byte2(int value)942 private static int byte2(int value) { 943 return (value >> 16) & 0xff; 944 } 945 byte3(int value)946 private static int byte3(int value) { 947 return value >>> 24; 948 } 949 nibble0(int value)950 private static int nibble0(int value) { 951 return value & 0xf; 952 } 953 nibble1(int value)954 private static int nibble1(int value) { 955 return (value >> 4) & 0xf; 956 } 957 nibble2(int value)958 private static int nibble2(int value) { 959 return (value >> 8) & 0xf; 960 } 961 nibble3(int value)962 private static int nibble3(int value) { 963 return (value >> 12) & 0xf; 964 } 965 } 966