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 {
FORMAT_00X()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 
FORMAT_10X()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 
FORMAT_12X()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 
FORMAT_11N()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 
FORMAT_11X()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 
FORMAT_10T()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 
FORMAT_20T()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 
FORMAT_20BC()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 
FORMAT_22X()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 
FORMAT_21T()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 
FORMAT_21S()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 
FORMAT_21H()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 
FORMAT_21C()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 
FORMAT_23X()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 
FORMAT_22B()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 
FORMAT_22T()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 
FORMAT_22S()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 
FORMAT_22C()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 
FORMAT_22CS()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 
FORMAT_30T()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 
FORMAT_32X()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 
FORMAT_31I()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 
FORMAT_31T()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 
FORMAT_31C()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 
FORMAT_35C()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 
FORMAT_35MS()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 
FORMAT_35MI()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 
FORMAT_3RC()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 
FORMAT_3RMS()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 
FORMAT_3RMI()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 
FORMAT_51L()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 
FORMAT_33X()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 
FORMAT_32S()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 
FORMAT_40SC()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 
FORMAT_41C()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 
FORMAT_52C()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 
FORMAT_5RC()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 
FORMAT_PACKED_SWITCH_PAYLOAD()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 
FORMAT_SPARSE_SWITCH_PAYLOAD()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 
FORMAT_FILL_ARRAY_DATA_PAYLOAD()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      */
decode(int opcodeUnit, CodeInput in)890     public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in)
891         throws EOFException;
892 
893     /**
894      * Encodes the given instruction.
895      */
encode(DecodedInstruction insn, CodeOutput out)896     public abstract void encode(DecodedInstruction insn, CodeOutput out);
897 
898     /**
899      * Helper method that decodes any of the register-list formats.
900      */
decodeRegisterList( InstructionCodec format, int opcodeUnit, CodeInput in)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      */
encodeRegisterList(DecodedInstruction insn, CodeOutput out)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      */
decodeRegisterRange( InstructionCodec format, int opcodeUnit, CodeInput in)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      */
encodeRegisterRange(DecodedInstruction insn, CodeOutput out)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 
codeUnit(int lowByte, int highByte)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 
codeUnit(int nibble0, int nibble1, int nibble2, int nibble3)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 
makeByte(int lowNibble, int highNibble)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 
asUnsignedUnit(int value)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 
unit0(int value)1044     private static short unit0(int value) {
1045         return (short) value;
1046     }
1047 
unit1(int value)1048     private static short unit1(int value) {
1049         return (short) (value >> 16);
1050     }
1051 
unit0(long value)1052     private static short unit0(long value) {
1053         return (short) value;
1054     }
1055 
unit1(long value)1056     private static short unit1(long value) {
1057         return (short) (value >> 16);
1058     }
1059 
unit2(long value)1060     private static short unit2(long value) {
1061         return (short) (value >> 32);
1062     }
1063 
unit3(long value)1064     private static short unit3(long value) {
1065         return (short) (value >> 48);
1066     }
1067 
byte0(int value)1068     private static int byte0(int value) {
1069         return value & 0xff;
1070     }
1071 
byte1(int value)1072     private static int byte1(int value) {
1073         return (value >> 8) & 0xff;
1074     }
1075 
byte2(int value)1076     private static int byte2(int value) {
1077         return (value >> 16) & 0xff;
1078     }
1079 
byte3(int value)1080     private static int byte3(int value) {
1081         return value >>> 24;
1082     }
1083 
nibble0(int value)1084     private static int nibble0(int value) {
1085         return value & 0xf;
1086     }
1087 
nibble1(int value)1088     private static int nibble1(int value) {
1089         return (value >> 4) & 0xf;
1090     }
1091 
nibble2(int value)1092     private static int nibble2(int value) {
1093         return (value >> 8) & 0xf;
1094     }
1095 
nibble3(int value)1096     private static int nibble3(int value) {
1097         return (value >> 12) & 0xf;
1098     }
1099 }
1100