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