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