CodeReader.java revision e31a42442bbd2cdc69e959f5209b793cf0aa7217
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
17package com.android.dx.io;
18
19import com.android.dx.dex.DexException;
20import java.util.BitSet;
21
22/**
23 * Walks through a block of code and calls visitor call backs.
24 */
25public final class CodeReader {
26
27    private final Instruction[] instructions = new Instruction[] {
28            // 0x00...0x0f
29            new Instruction(1, "nop"),
30            new Instruction(1, "move vA, vB"),
31            new Instruction(2, "move/from vAA, vBBBB"),
32            new Instruction(3, "move/16 vAAAA, vBBBB"),
33            new Instruction(1, "move-wide, vA, vB"),
34            new Instruction(2, "move-wide/from16 vAA, vBBBB"),
35            new Instruction(3, "move-wide/from16 vAAAA, vBBBB"),
36            new Instruction(1, "move-object vA, vB"),
37            new Instruction(2, "move-object/from16 vAA, vBBBB"),
38            new Instruction(3, "move-object/16 vAAAA, vBBBB"),
39            new Instruction(1, "move-result vAA"),
40            new Instruction(1, "move-result-wide vAA"),
41            new Instruction(1, "move-result-object vAA"),
42            new Instruction(1, "move-exception vAA"),
43            new Instruction(1, "return void"),
44            new Instruction(1, "return vAA"),
45
46            // 0x10...0x1f
47            new Instruction(1, "return-wide vAA"),
48            new Instruction(1, "return-object vAA"),
49            new Instruction(1, "const/4 vA, #+B"),
50            new Instruction(2, "const/16 vAA, #+BBBB"),
51            new Instruction(3, "const vAA, #+BBBBBBBB"),
52            new Instruction(2, "const/high16 vAA, #+BBBB0000"),
53            new Instruction(2, "const-wide/16 vAA, #+BBBB"),
54            new Instruction(3, "const-wide/32 vAA, #+BBBBBBBB"),
55            new Instruction(5, "const-wide vAA, #+BBBBBBBBBBBBBBBB"),
56            new Instruction(2, "const-wide/high16 vAA, #+BBBB000000000000"),
57            new Instruction(2, "const-string vAA, string@BBBB"),
58            new Instruction(3, "const-string/jumbo vAA, string@BBBBBBBB"),
59            new Instruction(2, "const-class vAA, type@BBBB"),
60            new Instruction(1, "monitor-enter vAA"),
61            new Instruction(1, "monitor-exit vAA"),
62            new Instruction(2, "check-cast vAA type@BBBB"),
63
64            // 0x20...0x2f
65            new Instruction(2, "instance-of vA, vB, type@CCCC"),
66            new Instruction(1, "array-length vA, vB"),
67            new Instruction(2, "new-instance vAA, type@BBBB"),
68            new Instruction(2, "new-array vA, vB, type@CCCC"),
69            new Instruction(3, "filled-new-array {vD, vE, vF, vG, vA}, type@CCCC"),
70            new Instruction(3, "filled-new-array/range {vCCCC..vNNNN}, type@BBBB"),
71            new FillArrayInstruction(3, "fill-array-data vAA, +BBBBBBBB"),
72            new Instruction(1, "throw vAA"),
73            new Instruction(1, "goto +AA"),
74            new Instruction(2, "goto/16 +AAAA"),
75            new Instruction(3, "goto/32 +AAAAAAAA"),
76            new PackedSwitchInstruction(3, "packed-switch vAA, +BBBBBBBB"),
77            new SparseSwitchInstruction(3, "sparse-switch vAA, +BBBBBBBB"),
78            new Instruction(2, "cmpl-float vAA, vBB, vCC"),
79            new Instruction(2, "cmpg-float vAA, vBB, vCC"),
80            new Instruction(2, "cmpl-double vAA, vBB, vCC"),
81
82            // 0x30...0x3f
83            new Instruction(2, "cmpg-double vAA, vBB, vCC"),
84            new Instruction(2, "cmp-long vAA, vBB, vCC"),
85            new Instruction(2, "if-eq vA, vB, +CCCC"),
86            new Instruction(2, "if-ne vA, vB, +CCCC"),
87            new Instruction(2, "if-lt vA, vB, +CCCC"),
88            new Instruction(2, "if-ge vA, vB, +CCCC"),
89            new Instruction(2, "if-gt vA, vB, +CCCC"),
90            new Instruction(2, "if-le vA, vB, +CCCC"),
91            new Instruction(2, "if-eqz vAA, +BBBB"),
92            new Instruction(2, "if-nez vAA, +BBBB"),
93            new Instruction(2, "if-ltz vAA, +BBBB"),
94            new Instruction(2, "if-gez vAA, +BBBB"),
95            new Instruction(2, "if-gtz vAA, +BBBB"),
96            new Instruction(2, "if-lez vAA, +BBBB"),
97            new UnusedInstruction(),
98            new UnusedInstruction(),
99
100            // 0x40...0x4f
101            new UnusedInstruction(),
102            new UnusedInstruction(),
103            new UnusedInstruction(),
104            new UnusedInstruction(),
105            new Instruction(2, "aget vAA, vBB, vCC"),
106            new Instruction(2, "aget-wide vAA, vBB, vCC"),
107            new Instruction(2, "aget-object vAA, vBB, vCC"),
108            new Instruction(2, "aget-boolean vAA, vBB, vCC"),
109            new Instruction(2, "aget-byte vAA, vBB, vCC"),
110            new Instruction(2, "aget-char vAA, vBB, vCC"),
111            new Instruction(2, "aget-short vAA, vBB, vCC"),
112            new Instruction(2, "aput vAA, vBB, vCC"),
113            new Instruction(2, "aput-wide vAA, vBB, vCC"),
114            new Instruction(2, "aput-object vAA, vBB, vCC"),
115            new Instruction(2, "aput-boolean vAA, vBB, vCC"),
116            new Instruction(2, "aput-byte vAA, vBB, vCC"),
117
118            // 0x50...0x5f
119            new Instruction(2, "aput-char vAA, vBB, vCC"),
120            new Instruction(2, "aput-short vAA, vBB, vCC"),
121            new Instruction(2, "iget vA, vB, field@CCCC"),
122            new Instruction(2, "iget-wide vA, vB, field@CCCC"),
123            new Instruction(2, "iget-object vA, vB, field@CCCC"),
124            new Instruction(2, "iget-boolean vA, vB, field@CCCC"),
125            new Instruction(2, "iget-byte vA, vB, field@CCCC"),
126            new Instruction(2, "iget-char vA, vB, field@CCCC"),
127            new Instruction(2, "iget-short vA, vB, field@CCCC"),
128            new Instruction(2, "iput vA, vB, field@CCCC"),
129            new Instruction(2, "iput-wide vA, vB, field@CCCC"),
130            new Instruction(2, "iput-object vA, vB, field@CCCC"),
131            new Instruction(2, "iput-boolean vA, vB, field@CCCC"),
132            new Instruction(2, "iput-byte vA, vB, field@CCCC"),
133            new Instruction(2, "iput-char vA, vB, field@CCCC"),
134            new Instruction(2, "iput-short vA, vB, field@CCCC"),
135
136            // 0x60...0x6f
137            new Instruction(2, "sget vAA, field@BBBB"),
138            new Instruction(2, "sget-wide vAA, field@BBBB"),
139            new Instruction(2, "sget-object vAA, field@BBBB"),
140            new Instruction(2, "sget-boolean vAA, field@BBBB"),
141            new Instruction(2, "sget-byte vAA, field@BBBB"),
142            new Instruction(2, "sget-char vAA, field@BBBB"),
143            new Instruction(2, "sget-short vAA, field@BBBB"),
144            new Instruction(2, "sput vAA, field@BBBB"),
145            new Instruction(2, "sput-wide vAA, field@BBBB"),
146            new Instruction(2, "sput-object vAA, field@BBBB"),
147            new Instruction(2, "sput-boolean vAA, field@BBBB"),
148            new Instruction(2, "sput-byte vAA, field@BBBB"),
149            new Instruction(2, "sput-char vAA, field@BBBB"),
150            new Instruction(2, "sput-short vAA, field@BBBB"),
151            new Instruction(3, "invoke-virtual {vD, vE, vF, vG, vA}, meth@CCCC"),
152            new Instruction(3, "invoke-super {vD, vE, vF, vG, vA}, meth@CCCC"),
153
154            // 0x70...0x7f
155            new Instruction(3, "invoke-direct {vD, vE, vF, vG, vA}, meth@CCCC"),
156            new Instruction(3, "invoke-static {vD, vE, vF, vG, vA}, meth@CCCC"),
157            new Instruction(3, "invoke-interface {vD, vE, vF, vG, vA}, meth@CCCC"),
158            new UnusedInstruction(),
159            new Instruction(3, "invoke-virtual/range {vCCCC..vNNNN}, meth@BBBB"),
160            new Instruction(3, "invoke-super/range {vCCCC..vNNNN}, meth@BBBB"),
161            new Instruction(3, "invoke-direct/range {vCCCC..vNNNN}, meth@BBBB"),
162            new Instruction(3, "invoke-static/range {vCCCC..vNNNN}, meth@BBBB"),
163            new Instruction(3, "invoke-interface/range {vCCCC..vNNNN}, meth@BBBB"),
164            new UnusedInstruction(),
165            new UnusedInstruction(),
166            new Instruction(1, "neg-int vA, vB"),
167            new Instruction(1, "not-int vA, vB"),
168            new Instruction(1, "neg-long vA, vB"),
169            new Instruction(1, "not-long vA, vB"),
170            new Instruction(1, "neg-float vA, vB"),
171
172            // 0x80...0x8f
173            new Instruction(1, "neg-double vA, vB"),
174            new Instruction(1, "int-to-long vA, vB"),
175            new Instruction(1, "int-to-float vA, vB"),
176            new Instruction(1, "int-to-double vA, vB"),
177            new Instruction(1, "long-to-int vA, vB"),
178            new Instruction(1, "long-to-float vA, vB"),
179            new Instruction(1, "long-to-double vA, vB"),
180            new Instruction(1, "float-to-int vA, vB"),
181            new Instruction(1, "float-to-long vA, vB"),
182            new Instruction(1, "float-to-double vA, vB"),
183            new Instruction(1, "double-to-int vA, vB"),
184            new Instruction(1, "double-to-long vA, vB"),
185            new Instruction(1, "double-to-float vA, vB"),
186            new Instruction(1, "int-to-byte vA, vB"),
187            new Instruction(1, "int-to-char vA, vB"),
188            new Instruction(1, "int-to-short vA, vB"),
189
190            // 0x90...0x9f
191            new Instruction(2, "add-int vAA, vBB, vCC"),
192            new Instruction(2, "sub-int vAA, vBB, vCC"),
193            new Instruction(2, "mul-int vAA, vBB, vCC"),
194            new Instruction(2, "div-int vAA, vBB, vCC"),
195            new Instruction(2, "rem-int vAA, vBB, vCC"),
196            new Instruction(2, "and-int vAA, vBB, vCC"),
197            new Instruction(2, "or-int vAA, vBB, vCC"),
198            new Instruction(2, "xor-int vAA, vBB, vCC"),
199            new Instruction(2, "shl-int vAA, vBB, vCC"),
200            new Instruction(2, "shr-int vAA, vBB, vCC"),
201            new Instruction(2, "ushr-int vAA, vBB, vCC"),
202            new Instruction(2, "add-long vAA, vBB, vCC"),
203            new Instruction(2, "sub-long vAA, vBB, vCC"),
204            new Instruction(2, "mul-long vAA, vBB, vCC"),
205            new Instruction(2, "div-long vAA, vBB, vCC"),
206            new Instruction(2, "rem-long vAA, vBB, vCC"),
207
208            // 0xa0...0xaf
209            new Instruction(2, "and-long vAA, vBB, vCC"),
210            new Instruction(2, "or-long vAA, vBB, vCC"),
211            new Instruction(2, "xor-long vAA, vBB, vCC"),
212            new Instruction(2, "shl-long vAA, vBB, vCC"),
213            new Instruction(2, "shr-long vAA, vBB, vCC"),
214            new Instruction(2, "ushr-long vAA, vBB, vCC"),
215            new Instruction(2, "add-float vAA, vBB, vCC"),
216            new Instruction(2, "sub-float vAA, vBB, vCC"),
217            new Instruction(2, "mul-float vAA, vBB, vCC"),
218            new Instruction(2, "div-float vAA, vBB, vCC"),
219            new Instruction(2, "rem-float vAA, vBB, vCC"),
220            new Instruction(2, "add-double vAA, vBB, vCC"),
221            new Instruction(2, "sub-double vAA, vBB, vCC"),
222            new Instruction(2, "mul-double vAA, vBB, vCC"),
223            new Instruction(2, "div-double vAA, vBB, vCC"),
224            new Instruction(2, "rem-double vAA, vBB, vCC"),
225
226            // 0xb0..0xbf
227            new Instruction(1, "add-int/2addr vA, vB"),
228            new Instruction(1, "sub-int/2addr vA, vB"),
229            new Instruction(1, "mul-int/2addr vA, vB"),
230            new Instruction(1, "div-int/2addr vA, vB"),
231            new Instruction(1, "rem-int/2addr vA, vB"),
232            new Instruction(1, "and-int/2addr vA, vB"),
233            new Instruction(1, "or-int/2addr vA, vB"),
234            new Instruction(1, "xor-int/2addr vA, vB"),
235            new Instruction(1, "shl-int/2addr vA, vB"),
236            new Instruction(1, "shr-int/2addr vA, vB"),
237            new Instruction(1, "ushr-int/2addr vA, vB"),
238            new Instruction(1, "add-long/2addr vA, vB"),
239            new Instruction(1, "sub-long/2addr vA, vB"),
240            new Instruction(1, "mul-long/2addr vA, vB"),
241            new Instruction(1, "div-long/2addr vA, vB"),
242            new Instruction(1, "rem-long/2addr vA, vB"),
243
244            // 0xc0...0xcf
245            new Instruction(1, "and-long/2addr vA, vB"),
246            new Instruction(1, "or-long/2addr vA, vB"),
247            new Instruction(1, "xor-long/2addr vA, vB"),
248            new Instruction(1, "shl-long/2addr vA, vB"),
249            new Instruction(1, "shr-long/2addr vA, vB"),
250            new Instruction(1, "ushr-long/2addr vA, vB"),
251            new Instruction(1, "add-float/2addr vA, vB"),
252            new Instruction(1, "sub-float/2addr vA, vB"),
253            new Instruction(1, "mul-float/2addr vA, vB"),
254            new Instruction(1, "div-float/2addr vA, vB"),
255            new Instruction(1, "rem-float/2addr vA, vB"),
256            new Instruction(1, "add-double/2addr vA, vB"),
257            new Instruction(1, "sub-double/2addr vA, vB"),
258            new Instruction(1, "mul-double/2addr vA, vB"),
259            new Instruction(1, "div-double/2addr vA, vB"),
260            new Instruction(1, "rem-double/2addr vA, vB"),
261
262            // 0xd0...0xdf
263            new Instruction(2, "add-int/lit16 vA, vB, #+CCCC"),
264            new Instruction(2, "rsub-int (reverse subtract) vA, vB, #+CCCC"),
265            new Instruction(2, "mul-int/lit16 vA, vB, #+CCCC"),
266            new Instruction(2, "div-int/lit16 vA, vB, #+CCCC"),
267            new Instruction(2, "rem-int/lit16 vA, vB, #+CCCC"),
268            new Instruction(2, "and-int/lit16 vA, vB, #+CCCC"),
269            new Instruction(2, "or-int/lit16 vA, vB, #+CCCC"),
270            new Instruction(2, "xor-int/lit16 vA, vB, #+CCCC"),
271            new Instruction(2, "add-int/lit8 vAA, vBB, #+CC"),
272            new Instruction(2, "rsub-int/lit8 vAA, vBB, #+CC"),
273            new Instruction(2, "mul-int/lit8 vAA, vBB, #+CC"),
274            new Instruction(2, "div-int/lit8 vAA, vBB, #+CC"),
275            new Instruction(2, "rem-int/lit8 vAA, vBB, #+CC"),
276            new Instruction(2, "and-int/lit8 vAA, vBB, #+CC"),
277            new Instruction(2, "or-int/lit8 vAA, vBB, #+CC"),
278            new Instruction(2, "xor-int/lit8 vAA, vBB, #+CC"),
279
280            // 0xe0...0xef
281            new Instruction(2, "shl-int/lit8 vAA, vBB, #+CC"),
282            new Instruction(2, "shr-int/lit8 vAA, vBB, #+CC"),
283            new Instruction(2, "ushr-int/lit8 vAA, vBB, #+CC"),
284    };
285
286    /**
287     * Sets {@code visitor} as the visitor for all string instructions.
288     */
289    public void setStringVisitor(Visitor visitor) {
290        instructions[0x1a].setVisitor("const-string vAA, string@BBBB", visitor);
291    }
292
293    /**
294     * Sets {@code visitor} as the visitor for all jumbo string instructions.
295     */
296    public void setJumboStringVisitor(Visitor visitor) {
297        instructions[0x1b].setVisitor("const-string/jumbo vAA, string@BBBBBBBB", visitor);
298    }
299
300    /**
301     * Sets {@code visitor} as the visitor for all type instructions.
302     */
303    public void setTypeVisitor(Visitor visitor) {
304        instructions[0x1c].setVisitor("const-class vAA, type@BBBB", visitor);
305        instructions[0x1f].setVisitor("check-cast vAA type@BBBB", visitor);
306        instructions[0x20].setVisitor("instance-of vA, vB, type@CCCC", visitor);
307        instructions[0x22].setVisitor("new-instance vAA, type@BBBB", visitor);
308        instructions[0x23].setVisitor("new-array vA, vB, type@CCCC", visitor);
309        instructions[0x24].setVisitor("filled-new-array {vD, vE, vF, vG, vA}, type@CCCC", visitor);
310        instructions[0x25].setVisitor("filled-new-array/range {vCCCC..vNNNN}, type@BBBB", visitor);
311    }
312
313    /**
314     * Sets {@code visitor} as the visitor for all field instructions.
315     */
316    public void setFieldVisitor(Visitor visitor) {
317        instructions[0x52].setVisitor("iget vA, vB, field@CCCC", visitor);
318        instructions[0x53].setVisitor("iget-wide vA, vB, field@CCCC", visitor);
319        instructions[0x54].setVisitor("iget-object vA, vB, field@CCCC", visitor);
320        instructions[0x55].setVisitor("iget-boolean vA, vB, field@CCCC", visitor);
321        instructions[0x56].setVisitor("iget-byte vA, vB, field@CCCC", visitor);
322        instructions[0x57].setVisitor("iget-char vA, vB, field@CCCC", visitor);
323        instructions[0x58].setVisitor("iget-short vA, vB, field@CCCC", visitor);
324        instructions[0x59].setVisitor("iput vA, vB, field@CCCC", visitor);
325        instructions[0x5a].setVisitor("iput-wide vA, vB, field@CCCC", visitor);
326        instructions[0x5b].setVisitor("iput-object vA, vB, field@CCCC", visitor);
327        instructions[0x5c].setVisitor("iput-boolean vA, vB, field@CCCC", visitor);
328        instructions[0x5d].setVisitor("iput-byte vA, vB, field@CCCC", visitor);
329        instructions[0x5e].setVisitor("iput-char vA, vB, field@CCCC", visitor);
330        instructions[0x5f].setVisitor("iput-short vA, vB, field@CCCC", visitor);
331        instructions[0x60].setVisitor("sget vAA, field@BBBB", visitor);
332        instructions[0x61].setVisitor("sget-wide vAA, field@BBBB", visitor);
333        instructions[0x62].setVisitor("sget-object vAA, field@BBBB", visitor);
334        instructions[0x63].setVisitor("sget-boolean vAA, field@BBBB", visitor);
335        instructions[0x64].setVisitor("sget-byte vAA, field@BBBB", visitor);
336        instructions[0x65].setVisitor("sget-char vAA, field@BBBB", visitor);
337        instructions[0x66].setVisitor("sget-short vAA, field@BBBB", visitor);
338        instructions[0x67].setVisitor("sput vAA, field@BBBB", visitor);
339        instructions[0x68].setVisitor("sput-wide vAA, field@BBBB", visitor);
340        instructions[0x69].setVisitor("sput-object vAA, field@BBBB", visitor);
341        instructions[0x6a].setVisitor("sput-boolean vAA, field@BBBB", visitor);
342        instructions[0x6b].setVisitor("sput-byte vAA, field@BBBB", visitor);
343        instructions[0x6c].setVisitor("sput-char vAA, field@BBBB", visitor);
344        instructions[0x6d].setVisitor("sput-short vAA, field@BBBB", visitor);
345    }
346
347    /**
348     * Sets {@code visitor} as the visitor for all method instructions.
349     */
350    public void setMethodVisitor(Visitor visitor) {
351        instructions[0x6e].setVisitor("invoke-virtual {vD, vE, vF, vG, vA}, meth@CCCC", visitor);
352        instructions[0x6f].setVisitor("invoke-super {vD, vE, vF, vG, vA}, meth@CCCC", visitor);
353        instructions[0x70].setVisitor("invoke-direct {vD, vE, vF, vG, vA}, meth@CCCC", visitor);
354        instructions[0x71].setVisitor("invoke-static {vD, vE, vF, vG, vA}, meth@CCCC", visitor);
355        instructions[0x72].setVisitor("invoke-interface {vD, vE, vF, vG, vA}, meth@CCCC", visitor);
356        instructions[0x74].setVisitor("invoke-virtual/range {vCCCC..vNNNN}, meth@BBBB", visitor);
357        instructions[0x75].setVisitor("invoke-super/range {vCCCC..vNNNN}, meth@BBBB", visitor);
358        instructions[0x76].setVisitor("invoke-direct/range {vCCCC..vNNNN}, meth@BBBB", visitor);
359        instructions[0x77].setVisitor("invoke-static/range {vCCCC..vNNNN}, meth@BBBB", visitor);
360        instructions[0x78].setVisitor("invoke-interface/range {vCCCC..vNNNN}, meth@BBBB", visitor);
361    }
362
363    public void visitAll(short[] instructions) throws DexException {
364        BitSet skippedInstructions = new BitSet();
365
366        for (int i = 0; i < instructions.length; ) {
367            if (skippedInstructions.get(i)) {
368                i++;
369                continue;
370            }
371
372            int index = instructions[i] & 0xFF;
373            if (index < 0 || index >= this.instructions.length) {
374                throw new DexException("Unhandled instruction at " + i
375                        + ": " + Integer.toHexString(index));
376            }
377
378            Instruction instruction = this.instructions[index];
379            instruction.mask(instructions, i, skippedInstructions);
380            if (instruction.visitor != null) {
381                instruction.visitor.visit(instruction, instructions, i);
382            }
383            i += instruction.codeUnits;
384        }
385    }
386
387    public static class Instruction {
388        private final String name;
389        private final int codeUnits;
390        private Visitor visitor;
391
392        private Instruction(int codeUnits, String name) {
393            this.name = name;
394            this.codeUnits = codeUnits;
395        }
396
397        public String getName() {
398            return name;
399        }
400
401        /**
402         * Sets the visitor to be notified when this instruction is encountered,
403         * or null if this instruction has no visitor.
404         */
405        public void setVisitor(String name, Visitor visitor) {
406            if (!this.name.equals(name)) {
407                throw new IllegalArgumentException("Expected " + this.name + " but was " + name);
408            }
409            this.visitor = visitor;
410        }
411
412        protected void mask(short[] instructions, int offset, BitSet skippedInstructions) {}
413
414        @Override public String toString() {
415            return name;
416        }
417    }
418
419    public interface Visitor {
420        void visit(Instruction instruction, short[] instructions, int offset);
421    }
422
423    private static class UnusedInstruction extends Instruction {
424        UnusedInstruction() {
425            super(1, "unused");
426        }
427    }
428
429    private static class PackedSwitchInstruction extends Instruction {
430        public PackedSwitchInstruction(int codeUnits, String name) {
431            super(codeUnits, name);
432        }
433        @Override protected void mask(short[] instructions, int i, BitSet skippedInstructions) {
434            int offset = (instructions[i + 1] & 0xFFFF)
435                    + ((instructions[i + 2] & 0xFFFF) << 16);
436            if (instructions[i + offset] != 0x100) {
437                throw new DexException("Expected packed-switch pseudo-opcode but was 0x"
438                        + Integer.toHexString(instructions[i + offset]));
439            }
440            short size = instructions[i + offset + 1];
441            skippedInstructions.set(i + offset, i + offset + 4 + (size * 2));
442        }
443    }
444
445    private static class SparseSwitchInstruction extends Instruction {
446        public SparseSwitchInstruction(int codeUnits, String name) {
447            super(codeUnits, name);
448        }
449        @Override protected void mask(short[] instructions, int i, BitSet skippedInstructions) {
450            int offset = (instructions[i + 1] & 0xFFFF)
451                    + ((instructions[i + 2] & 0xFFFF) << 16);
452            if (instructions[i + offset] != 0x200) {
453                throw new DexException("Expected sparse-switch pseudo-opcode but was 0x"
454                        + Integer.toHexString(instructions[i + offset]));
455            }
456            short size = instructions[i + offset + 1];
457            skippedInstructions.set(i + offset, i + offset + 2 + (size * 4));
458        }
459    }
460
461    private static class FillArrayInstruction extends Instruction {
462        public FillArrayInstruction(int codeUnits, String name) {
463            super(codeUnits, name);
464        }
465        @Override protected void mask(short[] instructions, int i, BitSet skippedInstructions) {
466            int offset = (instructions[i + 1] & 0xFFFF)
467                    + ((instructions[i + 2] & 0xFFFF) << 16);
468            if (instructions[i + offset] != 0x300) {
469                throw new DexException("Expected fill-array-data pseudo-opcode but was 0x"
470                        + Integer.toHexString(instructions[i + offset]));
471            }
472            int bytesPerElement = instructions[i + offset + 1];
473            int size = (instructions[i + offset + 2] & 0xFFFF)
474                    + ((instructions[i + offset + 3] & 0xFFFF) << 4);
475            int totalBytes = size * bytesPerElement;
476            int totalShorts = (totalBytes + 1) / 2; // round up!
477            skippedInstructions.set(i + offset, i + offset + 4 + totalShorts);
478        }
479    }
480}
481