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