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