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.instructions;
18
19import com.android.dx.io.IndexType;
20import com.android.dx.io.OpcodeInfo;
21import com.android.dx.io.Opcodes;
22import com.android.dx.util.DexException;
23import com.android.dx.util.Hex;
24import java.io.EOFException;
25
26/**
27 * A decoded Dalvik instruction. This consists of a format codec, a
28 * numeric opcode, an optional index type, and any additional
29 * arguments of the instruction. The additional arguments (if any) are
30 * represented as uninterpreted data.
31 *
32 * <p><b>Note:</b> The names of the arguments are <i>not</i> meant to
33 * match the names given in the Dalvik instruction format
34 * specification, specification which just names fields (somewhat)
35 * arbitrarily alphabetically from A. In this class, non-register
36 * fields are given descriptive names and register fields are
37 * consistently named alphabetically.</p>
38 */
39public abstract class DecodedInstruction {
40    /** non-null; instruction format / codec */
41    private final InstructionCodec format;
42
43    /** opcode number */
44    private final int opcode;
45
46    /** constant index argument */
47    private final int index;
48
49    /** null-ok; index type */
50    private final IndexType indexType;
51
52    /**
53     * target address argument. This is an absolute address, not just
54     * a signed offset. <b>Note:</b> The address is unsigned, even
55     * though it is stored in an {@code int}.
56     */
57    private final int target;
58
59    /**
60     * literal value argument; also used for special verification error
61     * constants (formats 20bc and 40sc) as well as should-be-zero values
62     * (formats 10x, 20t, 30t, and 32x)
63     */
64    private final long literal;
65
66    /**
67     * Decodes an instruction from the given input source.
68     */
69    public static DecodedInstruction decode(CodeInput in) throws EOFException {
70        int opcodeUnit = in.read();
71        int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit);
72        InstructionCodec format = OpcodeInfo.getFormat(opcode);
73
74        return format.decode(opcodeUnit, in);
75    }
76
77    /**
78     * Decodes an array of instructions. The result has non-null
79     * elements at each offset that represents the start of an
80     * instruction.
81     */
82    public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
83        int size = encodedInstructions.length;
84        DecodedInstruction[] decoded = new DecodedInstruction[size];
85        ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
86
87        try {
88            while (in.hasMore()) {
89                decoded[in.cursor()] = DecodedInstruction.decode(in);
90            }
91        } catch (EOFException ex) {
92            throw new DexException(ex);
93        }
94
95        return decoded;
96    }
97
98    /**
99     * Constructs an instance.
100     */
101    public DecodedInstruction(InstructionCodec format, int opcode,
102            int index, IndexType indexType, int target, long literal) {
103        if (format == null) {
104            throw new NullPointerException("format == null");
105        }
106
107        if (!Opcodes.isValidShape(opcode)) {
108            throw new IllegalArgumentException("invalid opcode");
109        }
110
111        this.format = format;
112        this.opcode = opcode;
113        this.index = index;
114        this.indexType = indexType;
115        this.target = target;
116        this.literal = literal;
117    }
118
119    public final InstructionCodec getFormat() {
120        return format;
121    }
122
123    public final int getOpcode() {
124        return opcode;
125    }
126
127    /**
128     * Gets the opcode, as a code unit.
129     */
130    public final short getOpcodeUnit() {
131        return (short) opcode;
132    }
133
134    public final int getIndex() {
135        return index;
136    }
137
138    /**
139     * Gets the index, as a code unit.
140     */
141    public final short getIndexUnit() {
142        return (short) index;
143    }
144
145    public final IndexType getIndexType() {
146        return indexType;
147    }
148
149    /**
150     * Gets the raw target.
151     */
152    public final int getTarget() {
153        return target;
154    }
155
156    /**
157     * Gets the target as a relative offset from the given address.
158     */
159    public final int getTarget(int baseAddress) {
160        return target - baseAddress;
161    }
162
163    /**
164     * Gets the target as a relative offset from the given base
165     * address, as a code unit. This will throw if the value is out of
166     * the range of a signed code unit.
167     */
168    public final short getTargetUnit(int baseAddress) {
169        int relativeTarget = getTarget(baseAddress);
170
171        if (relativeTarget != (short) relativeTarget) {
172            throw new DexException("Target out of range: "
173                    + Hex.s4(relativeTarget));
174        }
175
176        return (short) relativeTarget;
177    }
178
179    /**
180     * Gets the target as a relative offset from the given base
181     * address, masked to be a byte in size. This will throw if the
182     * value is out of the range of a signed byte.
183     */
184    public final int getTargetByte(int baseAddress) {
185        int relativeTarget = getTarget(baseAddress);
186
187        if (relativeTarget != (byte) relativeTarget) {
188            throw new DexException("Target out of range: "
189                    + Hex.s4(relativeTarget));
190        }
191
192        return relativeTarget & 0xff;
193    }
194
195    public final long getLiteral() {
196        return literal;
197    }
198
199    /**
200     * Gets the literal value, masked to be an int in size. This will
201     * throw if the value is out of the range of a signed int.
202     */
203    public final int getLiteralInt() {
204        if (literal != (int) literal) {
205            throw new DexException("Literal out of range: " + Hex.u8(literal));
206        }
207
208        return (int) literal;
209    }
210
211    /**
212     * Gets the literal value, as a code unit. This will throw if the
213     * value is out of the range of a signed code unit.
214     */
215    public final short getLiteralUnit() {
216        if (literal != (short) literal) {
217            throw new DexException("Literal out of range: " + Hex.u8(literal));
218        }
219
220        return (short) literal;
221    }
222
223    /**
224     * Gets the literal value, masked to be a byte in size. This will
225     * throw if the value is out of the range of a signed byte.
226     */
227    public final int getLiteralByte() {
228        if (literal != (byte) literal) {
229            throw new DexException("Literal out of range: " + Hex.u8(literal));
230        }
231
232        return (int) literal & 0xff;
233    }
234
235    /**
236     * Gets the literal value, masked to be a nibble in size. This
237     * will throw if the value is out of the range of a signed nibble.
238     */
239    public final int getLiteralNibble() {
240        if ((literal < -8) || (literal > 7)) {
241            throw new DexException("Literal out of range: " + Hex.u8(literal));
242        }
243
244        return (int) literal & 0xf;
245    }
246
247    public abstract int getRegisterCount();
248
249    public int getA() {
250        return 0;
251    }
252
253    public int getB() {
254        return 0;
255    }
256
257    public int getC() {
258        return 0;
259    }
260
261    public int getD() {
262        return 0;
263    }
264
265    public int getE() {
266        return 0;
267    }
268
269    /**
270     * Gets the register count, as a code unit. This will throw if the
271     * value is out of the range of an unsigned code unit.
272     */
273    public final short getRegisterCountUnit() {
274        int registerCount = getRegisterCount();
275
276        if ((registerCount & ~0xffff) != 0) {
277            throw new DexException("Register count out of range: "
278                    + Hex.u8(registerCount));
279        }
280
281        return (short) registerCount;
282    }
283
284    /**
285     * Gets the A register number, as a code unit. This will throw if the
286     * value is out of the range of an unsigned code unit.
287     */
288    public final short getAUnit() {
289        int a = getA();
290
291        if ((a & ~0xffff) != 0) {
292            throw new DexException("Register A out of range: " + Hex.u8(a));
293        }
294
295        return (short) a;
296    }
297
298    /**
299     * Gets the A register number, as a byte. This will throw if the
300     * value is out of the range of an unsigned byte.
301     */
302    public final short getAByte() {
303        int a = getA();
304
305        if ((a & ~0xff) != 0) {
306            throw new DexException("Register A out of range: " + Hex.u8(a));
307        }
308
309        return (short) a;
310    }
311
312    /**
313     * Gets the A register number, as a nibble. This will throw if the
314     * value is out of the range of an unsigned nibble.
315     */
316    public final short getANibble() {
317        int a = getA();
318
319        if ((a & ~0xf) != 0) {
320            throw new DexException("Register A out of range: " + Hex.u8(a));
321        }
322
323        return (short) a;
324    }
325
326    /**
327     * Gets the B register number, as a code unit. This will throw if the
328     * value is out of the range of an unsigned code unit.
329     */
330    public final short getBUnit() {
331        int b = getB();
332
333        if ((b & ~0xffff) != 0) {
334            throw new DexException("Register B out of range: " + Hex.u8(b));
335        }
336
337        return (short) b;
338    }
339
340    /**
341     * Gets the B register number, as a byte. This will throw if the
342     * value is out of the range of an unsigned byte.
343     */
344    public final short getBByte() {
345        int b = getB();
346
347        if ((b & ~0xff) != 0) {
348            throw new DexException("Register B out of range: " + Hex.u8(b));
349        }
350
351        return (short) b;
352    }
353
354    /**
355     * Gets the B register number, as a nibble. This will throw if the
356     * value is out of the range of an unsigned nibble.
357     */
358    public final short getBNibble() {
359        int b = getB();
360
361        if ((b & ~0xf) != 0) {
362            throw new DexException("Register B out of range: " + Hex.u8(b));
363        }
364
365        return (short) b;
366    }
367
368    /**
369     * Gets the C register number, as a code unit. This will throw if the
370     * value is out of the range of an unsigned code unit.
371     */
372    public final short getCUnit() {
373        int c = getC();
374
375        if ((c & ~0xffff) != 0) {
376            throw new DexException("Register C out of range: " + Hex.u8(c));
377        }
378
379        return (short) c;
380    }
381
382    /**
383     * Gets the C register number, as a byte. This will throw if the
384     * value is out of the range of an unsigned byte.
385     */
386    public final short getCByte() {
387        int c = getC();
388
389        if ((c & ~0xff) != 0) {
390            throw new DexException("Register C out of range: " + Hex.u8(c));
391        }
392
393        return (short) c;
394    }
395
396    /**
397     * Gets the C register number, as a nibble. This will throw if the
398     * value is out of the range of an unsigned nibble.
399     */
400    public final short getCNibble() {
401        int c = getC();
402
403        if ((c & ~0xf) != 0) {
404            throw new DexException("Register C out of range: " + Hex.u8(c));
405        }
406
407        return (short) c;
408    }
409
410    /**
411     * Gets the D register number, as a code unit. This will throw if the
412     * value is out of the range of an unsigned code unit.
413     */
414    public final short getDUnit() {
415        int d = getD();
416
417        if ((d & ~0xffff) != 0) {
418            throw new DexException("Register D out of range: " + Hex.u8(d));
419        }
420
421        return (short) d;
422    }
423
424    /**
425     * Gets the D register number, as a byte. This will throw if the
426     * value is out of the range of an unsigned byte.
427     */
428    public final short getDByte() {
429        int d = getD();
430
431        if ((d & ~0xff) != 0) {
432            throw new DexException("Register D out of range: " + Hex.u8(d));
433        }
434
435        return (short) d;
436    }
437
438    /**
439     * Gets the D register number, as a nibble. This will throw if the
440     * value is out of the range of an unsigned nibble.
441     */
442    public final short getDNibble() {
443        int d = getD();
444
445        if ((d & ~0xf) != 0) {
446            throw new DexException("Register D out of range: " + Hex.u8(d));
447        }
448
449        return (short) d;
450    }
451
452    /**
453     * Gets the E register number, as a nibble. This will throw if the
454     * value is out of the range of an unsigned nibble.
455     */
456    public final short getENibble() {
457        int e = getE();
458
459        if ((e & ~0xf) != 0) {
460            throw new DexException("Register E out of range: " + Hex.u8(e));
461        }
462
463        return (short) e;
464    }
465
466    /**
467     * Encodes this instance to the given output.
468     */
469    public final void encode(CodeOutput out) {
470        format.encode(this, out);
471    }
472
473    /**
474     * Returns an instance just like this one, except with the index replaced
475     * with the given one.
476     */
477    public abstract DecodedInstruction withIndex(int newIndex);
478}
479