OSDN Git Service

am b9f5c7aa: am 3ddb30bd: am 6bcf5d20: Merge "Obvious mix of = and =="
[android-x86/dalvik.git] / dx / src / com / android / dx / io / instructions / DecodedInstruction.java
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 import 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  */
39 public 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 (format 20bc) 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 }