• 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.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_PACKED_SWITCH_PAYLOAD()608     FORMAT_PACKED_SWITCH_PAYLOAD() {
609         @Override public DecodedInstruction decode(int opcodeUnit,
610                 CodeInput in) throws EOFException {
611             int baseAddress = in.baseAddressForCursor() - 1; // already read opcode
612             int size = in.read();
613             int firstKey = in.readInt();
614             int[] targets = new int[size];
615 
616             for (int i = 0; i < size; i++) {
617                 targets[i] = baseAddress + in.readInt();
618             }
619 
620             return new PackedSwitchPayloadDecodedInstruction(
621                     this, opcodeUnit, firstKey, targets);
622         }
623 
624         @Override public void encode(DecodedInstruction insn, CodeOutput out) {
625             PackedSwitchPayloadDecodedInstruction payload =
626                 (PackedSwitchPayloadDecodedInstruction) insn;
627             int[] targets = payload.getTargets();
628             int baseAddress = out.baseAddressForCursor();
629 
630             out.write(payload.getOpcodeUnit());
631             out.write(asUnsignedUnit(targets.length));
632             out.writeInt(payload.getFirstKey());
633 
634             for (int target : targets) {
635                 out.writeInt(target - baseAddress);
636             }
637         }
638     },
639 
FORMAT_SPARSE_SWITCH_PAYLOAD()640     FORMAT_SPARSE_SWITCH_PAYLOAD() {
641         @Override public DecodedInstruction decode(int opcodeUnit,
642                 CodeInput in) throws EOFException {
643             int baseAddress = in.baseAddressForCursor() - 1; // already read opcode
644             int size = in.read();
645             int[] keys = new int[size];
646             int[] targets = new int[size];
647 
648             for (int i = 0; i < size; i++) {
649                 keys[i] = in.readInt();
650             }
651 
652             for (int i = 0; i < size; i++) {
653                 targets[i] = baseAddress + in.readInt();
654             }
655 
656             return new SparseSwitchPayloadDecodedInstruction(
657                     this, opcodeUnit, keys, targets);
658         }
659 
660         @Override public void encode(DecodedInstruction insn, CodeOutput out) {
661             SparseSwitchPayloadDecodedInstruction payload =
662                 (SparseSwitchPayloadDecodedInstruction) insn;
663             int[] keys = payload.getKeys();
664             int[] targets = payload.getTargets();
665             int baseAddress = out.baseAddressForCursor();
666 
667             out.write(payload.getOpcodeUnit());
668             out.write(asUnsignedUnit(targets.length));
669 
670             for (int key : keys) {
671                 out.writeInt(key);
672             }
673 
674             for (int target : targets) {
675                 out.writeInt(target - baseAddress);
676             }
677         }
678     },
679 
FORMAT_FILL_ARRAY_DATA_PAYLOAD()680     FORMAT_FILL_ARRAY_DATA_PAYLOAD() {
681         @Override public DecodedInstruction decode(int opcodeUnit,
682                 CodeInput in) throws EOFException {
683             int elementWidth = in.read();
684             int size = in.readInt();
685 
686             switch (elementWidth) {
687                 case 1: {
688                     byte[] array = new byte[size];
689                     boolean even = true;
690                     for (int i = 0, value = 0; i < size; i++, even = !even) {
691                         if (even) {
692                             value = in.read();
693                         }
694                         array[i] = (byte) (value & 0xff);
695                         value >>= 8;
696                     }
697                     return new FillArrayDataPayloadDecodedInstruction(
698                             this, opcodeUnit, array);
699                 }
700                 case 2: {
701                     short[] array = new short[size];
702                     for (int i = 0; i < size; i++) {
703                         array[i] = (short) in.read();
704                     }
705                     return new FillArrayDataPayloadDecodedInstruction(
706                             this, opcodeUnit, array);
707                 }
708                 case 4: {
709                     int[] array = new int[size];
710                     for (int i = 0; i < size; i++) {
711                         array[i] = in.readInt();
712                     }
713                     return new FillArrayDataPayloadDecodedInstruction(
714                             this, opcodeUnit, array);
715                 }
716                 case 8: {
717                     long[] array = new long[size];
718                     for (int i = 0; i < size; i++) {
719                         array[i] = in.readLong();
720                     }
721                     return new FillArrayDataPayloadDecodedInstruction(
722                             this, opcodeUnit, array);
723                 }
724             }
725 
726             throw new DexException("bogus element_width: "
727                     + Hex.u2(elementWidth));
728         }
729 
730         @Override public void encode(DecodedInstruction insn, CodeOutput out) {
731             FillArrayDataPayloadDecodedInstruction payload =
732                 (FillArrayDataPayloadDecodedInstruction) insn;
733             short elementWidth = payload.getElementWidthUnit();
734             Object data = payload.getData();
735 
736             out.write(payload.getOpcodeUnit());
737             out.write(elementWidth);
738             out.writeInt(payload.getSize());
739 
740             switch (elementWidth) {
741                 case 1: out.write((byte[]) data);  break;
742                 case 2: out.write((short[]) data); break;
743                 case 4: out.write((int[]) data);   break;
744                 case 8: out.write((long[]) data);  break;
745                 default: {
746                     throw new DexException("bogus element_width: "
747                             + Hex.u2(elementWidth));
748                 }
749             }
750         }
751     };
752 
753     /**
754      * Decodes an instruction specified by the given opcode unit, reading
755      * any required additional code units from the given input source.
756      */
decode(int opcodeUnit, CodeInput in)757     public abstract DecodedInstruction decode(int opcodeUnit, CodeInput in)
758         throws EOFException;
759 
760     /**
761      * Encodes the given instruction.
762      */
encode(DecodedInstruction insn, CodeOutput out)763     public abstract void encode(DecodedInstruction insn, CodeOutput out);
764 
765     /**
766      * Helper method that decodes any of the register-list formats.
767      */
decodeRegisterList( InstructionCodec format, int opcodeUnit, CodeInput in)768     private static DecodedInstruction decodeRegisterList(
769             InstructionCodec format, int opcodeUnit, CodeInput in)
770             throws EOFException {
771         int opcode = byte0(opcodeUnit);
772         int e = nibble2(opcodeUnit);
773         int registerCount = nibble3(opcodeUnit);
774         int index = in.read();
775         int abcd = in.read();
776         int a = nibble0(abcd);
777         int b = nibble1(abcd);
778         int c = nibble2(abcd);
779         int d = nibble3(abcd);
780         IndexType indexType = OpcodeInfo.getIndexType(opcode);
781 
782         // TODO: Having to switch like this is less than ideal.
783         switch (registerCount) {
784             case 0:
785                 return new ZeroRegisterDecodedInstruction(
786                         format, opcode, index, indexType,
787                         0, 0L);
788             case 1:
789                 return new OneRegisterDecodedInstruction(
790                         format, opcode, index, indexType,
791                         0, 0L,
792                         a);
793             case 2:
794                 return new TwoRegisterDecodedInstruction(
795                         format, opcode, index, indexType,
796                         0, 0L,
797                         a, b);
798             case 3:
799                 return new ThreeRegisterDecodedInstruction(
800                         format, opcode, index, indexType,
801                         0, 0L,
802                         a, b, c);
803             case 4:
804                 return new FourRegisterDecodedInstruction(
805                         format, opcode, index, indexType,
806                         0, 0L,
807                         a, b, c, d);
808             case 5:
809                 return new FiveRegisterDecodedInstruction(
810                         format, opcode, index, indexType,
811                         0, 0L,
812                         a, b, c, d, e);
813         }
814 
815         throw new DexException("bogus registerCount: "
816                 + Hex.uNibble(registerCount));
817     }
818 
819     /**
820      * Helper method that encodes any of the register-list formats.
821      */
encodeRegisterList(DecodedInstruction insn, CodeOutput out)822     private static void encodeRegisterList(DecodedInstruction insn,
823             CodeOutput out) {
824         out.write(codeUnit(insn.getOpcode(),
825                         makeByte(insn.getE(), insn.getRegisterCount())),
826                 insn.getIndexUnit(),
827                 codeUnit(insn.getA(), insn.getB(), insn.getC(), insn.getD()));
828     }
829 
830     /**
831      * Helper method that decodes any of the three-unit register-range formats.
832      */
decodeRegisterRange( InstructionCodec format, int opcodeUnit, CodeInput in)833     private static DecodedInstruction decodeRegisterRange(
834             InstructionCodec format, int opcodeUnit, CodeInput in)
835             throws EOFException {
836         int opcode = byte0(opcodeUnit);
837         int registerCount = byte1(opcodeUnit);
838         int index = in.read();
839         int a = in.read();
840         IndexType indexType = OpcodeInfo.getIndexType(opcode);
841         return new RegisterRangeDecodedInstruction(
842                 format, opcode, index, indexType,
843                 0, 0L,
844                 a, registerCount);
845     }
846 
847     /**
848      * Helper method that encodes any of the three-unit register-range formats.
849      */
encodeRegisterRange(DecodedInstruction insn, CodeOutput out)850     private static void encodeRegisterRange(DecodedInstruction insn,
851             CodeOutput out) {
852         out.write(codeUnit(insn.getOpcode(), insn.getRegisterCount()),
853                 insn.getIndexUnit(),
854                 insn.getAUnit());
855     }
856 
codeUnit(int lowByte, int highByte)857     private static short codeUnit(int lowByte, int highByte) {
858         if ((lowByte & ~0xff) != 0) {
859             throw new IllegalArgumentException("bogus lowByte");
860         }
861 
862         if ((highByte & ~0xff) != 0) {
863             throw new IllegalArgumentException("bogus highByte");
864         }
865 
866         return (short) (lowByte | (highByte << 8));
867     }
868 
codeUnit(int nibble0, int nibble1, int nibble2, int nibble3)869     private static short codeUnit(int nibble0, int nibble1, int nibble2,
870             int nibble3) {
871         if ((nibble0 & ~0xf) != 0) {
872             throw new IllegalArgumentException("bogus nibble0");
873         }
874 
875         if ((nibble1 & ~0xf) != 0) {
876             throw new IllegalArgumentException("bogus nibble1");
877         }
878 
879         if ((nibble2 & ~0xf) != 0) {
880             throw new IllegalArgumentException("bogus nibble2");
881         }
882 
883         if ((nibble3 & ~0xf) != 0) {
884             throw new IllegalArgumentException("bogus nibble3");
885         }
886 
887         return (short) (nibble0 | (nibble1 << 4)
888                 | (nibble2 << 8) | (nibble3 << 12));
889     }
890 
makeByte(int lowNibble, int highNibble)891     private static int makeByte(int lowNibble, int highNibble) {
892         if ((lowNibble & ~0xf) != 0) {
893             throw new IllegalArgumentException("bogus lowNibble");
894         }
895 
896         if ((highNibble & ~0xf) != 0) {
897             throw new IllegalArgumentException("bogus highNibble");
898         }
899 
900         return lowNibble | (highNibble << 4);
901     }
902 
asUnsignedUnit(int value)903     private static short asUnsignedUnit(int value) {
904         if ((value & ~0xffff) != 0) {
905             throw new IllegalArgumentException("bogus unsigned code unit");
906         }
907 
908         return (short) value;
909     }
910 
unit0(int value)911     private static short unit0(int value) {
912         return (short) value;
913     }
914 
unit1(int value)915     private static short unit1(int value) {
916         return (short) (value >> 16);
917     }
918 
unit0(long value)919     private static short unit0(long value) {
920         return (short) value;
921     }
922 
unit1(long value)923     private static short unit1(long value) {
924         return (short) (value >> 16);
925     }
926 
unit2(long value)927     private static short unit2(long value) {
928         return (short) (value >> 32);
929     }
930 
unit3(long value)931     private static short unit3(long value) {
932         return (short) (value >> 48);
933     }
934 
byte0(int value)935     private static int byte0(int value) {
936         return value & 0xff;
937     }
938 
byte1(int value)939     private static int byte1(int value) {
940         return (value >> 8) & 0xff;
941     }
942 
byte2(int value)943     private static int byte2(int value) {
944         return (value >> 16) & 0xff;
945     }
946 
byte3(int value)947     private static int byte3(int value) {
948         return value >>> 24;
949     }
950 
nibble0(int value)951     private static int nibble0(int value) {
952         return value & 0xf;
953     }
954 
nibble1(int value)955     private static int nibble1(int value) {
956         return (value >> 4) & 0xf;
957     }
958 
nibble2(int value)959     private static int nibble2(int value) {
960         return (value >> 8) & 0xf;
961     }
962 
nibble3(int value)963     private static int nibble3(int value) {
964         return (value >> 12) & 0xf;
965     }
966 }
967