2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.dx.io.instructions;
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;
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.
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>
39 public abstract class DecodedInstruction {
40 /** non-null; instruction format / codec */
41 private final InstructionCodec format;
44 private final int opcode;
46 /** constant index argument */
47 private final int index;
49 /** null-ok; index type */
50 private final IndexType indexType;
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}.
57 private final int target;
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)
64 private final long literal;
67 * Decodes an instruction from the given input source.
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);
74 return format.decode(opcodeUnit, in);
78 * Decodes an array of instructions. The result has non-null
79 * elements at each offset that represents the start of an
82 public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
83 int size = encodedInstructions.length;
84 DecodedInstruction[] decoded = new DecodedInstruction[size];
85 ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
88 while (in.hasMore()) {
89 decoded[in.cursor()] = DecodedInstruction.decode(in);
91 } catch (EOFException ex) {
92 throw new DexException(ex);
99 * Constructs an instance.
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");
107 if (!Opcodes.isValidShape(opcode)) {
108 throw new IllegalArgumentException("invalid opcode");
111 this.format = format;
112 this.opcode = opcode;
114 this.indexType = indexType;
115 this.target = target;
116 this.literal = literal;
119 public final InstructionCodec getFormat() {
123 public final int getOpcode() {
128 * Gets the opcode, as a code unit.
130 public final short getOpcodeUnit() {
131 return (short) opcode;
134 public final int getIndex() {
139 * Gets the index, as a code unit.
141 public final short getIndexUnit() {
142 return (short) index;
145 public final IndexType getIndexType() {
150 * Gets the raw target.
152 public final int getTarget() {
157 * Gets the target as a relative offset from the given address.
159 public final int getTarget(int baseAddress) {
160 return target - baseAddress;
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.
168 public final short getTargetUnit(int baseAddress) {
169 int relativeTarget = getTarget(baseAddress);
171 if (relativeTarget != (short) relativeTarget) {
172 throw new DexException("Target out of range: "
173 + Hex.s4(relativeTarget));
176 return (short) relativeTarget;
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.
184 public final int getTargetByte(int baseAddress) {
185 int relativeTarget = getTarget(baseAddress);
187 if (relativeTarget != (byte) relativeTarget) {
188 throw new DexException("Target out of range: "
189 + Hex.s4(relativeTarget));
192 return relativeTarget & 0xff;
195 public final long getLiteral() {
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.
203 public final int getLiteralInt() {
204 if (literal != (int) literal) {
205 throw new DexException("Literal out of range: " + Hex.u8(literal));
208 return (int) literal;
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.
215 public final short getLiteralUnit() {
216 if (literal != (short) literal) {
217 throw new DexException("Literal out of range: " + Hex.u8(literal));
220 return (short) literal;
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.
227 public final int getLiteralByte() {
228 if (literal != (byte) literal) {
229 throw new DexException("Literal out of range: " + Hex.u8(literal));
232 return (int) literal & 0xff;
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.
239 public final int getLiteralNibble() {
240 if ((literal < -8) || (literal > 7)) {
241 throw new DexException("Literal out of range: " + Hex.u8(literal));
244 return (int) literal & 0xf;
247 public abstract int getRegisterCount();
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.
273 public final short getRegisterCountUnit() {
274 int registerCount = getRegisterCount();
276 if ((registerCount & ~0xffff) != 0) {
277 throw new DexException("Register count out of range: "
278 + Hex.u8(registerCount));
281 return (short) registerCount;
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.
288 public final short getAUnit() {
291 if ((a & ~0xffff) != 0) {
292 throw new DexException("Register A out of range: " + Hex.u8(a));
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.
302 public final short getAByte() {
305 if ((a & ~0xff) != 0) {
306 throw new DexException("Register A out of range: " + Hex.u8(a));
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.
316 public final short getANibble() {
319 if ((a & ~0xf) != 0) {
320 throw new DexException("Register A out of range: " + Hex.u8(a));
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.
330 public final short getBUnit() {
333 if ((b & ~0xffff) != 0) {
334 throw new DexException("Register B out of range: " + Hex.u8(b));
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.
344 public final short getBByte() {
347 if ((b & ~0xff) != 0) {
348 throw new DexException("Register B out of range: " + Hex.u8(b));
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.
358 public final short getBNibble() {
361 if ((b & ~0xf) != 0) {
362 throw new DexException("Register B out of range: " + Hex.u8(b));
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.
372 public final short getCUnit() {
375 if ((c & ~0xffff) != 0) {
376 throw new DexException("Register C out of range: " + Hex.u8(c));
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.
386 public final short getCByte() {
389 if ((c & ~0xff) != 0) {
390 throw new DexException("Register C out of range: " + Hex.u8(c));
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.
400 public final short getCNibble() {
403 if ((c & ~0xf) != 0) {
404 throw new DexException("Register C out of range: " + Hex.u8(c));
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.
414 public final short getDUnit() {
417 if ((d & ~0xffff) != 0) {
418 throw new DexException("Register D out of range: " + Hex.u8(d));
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.
428 public final short getDByte() {
431 if ((d & ~0xff) != 0) {
432 throw new DexException("Register D out of range: " + Hex.u8(d));
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.
442 public final short getDNibble() {
445 if ((d & ~0xf) != 0) {
446 throw new DexException("Register D out of range: " + Hex.u8(d));
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.
456 public final short getENibble() {
459 if ((e & ~0xf) != 0) {
460 throw new DexException("Register E out of range: " + Hex.u8(e));
467 * Encodes this instance to the given output.
469 public final void encode(CodeOutput out) {
470 format.encode(this, out);
474 * Returns an instance just like this one, except with the index replaced
475 * with the given one.
477 public abstract DecodedInstruction withIndex(int newIndex);