• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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