OSDN Git Service

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