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.dex.DexException;
20 import com.android.dx.io.IndexType;
21 import com.android.dx.io.OpcodeInfo;
22 import com.android.dx.io.Opcodes;
23 import com.android.dx.util.Hex;
25 import java.io.EOFException;
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.
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>
40 public abstract class DecodedInstruction {
41 /** non-null; instruction format / codec */
42 private final InstructionCodec format;
45 private final int opcode;
47 /** constant index argument */
48 private final int index;
50 /** null-ok; index type */
51 private final IndexType indexType;
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}.
58 private final int target;
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)
65 private final long literal;
68 * Decodes an instruction from the given input source.
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);
75 return format.decode(opcodeUnit, in);
79 * Decodes an array of instructions. The result has non-null
80 * elements at each offset that represents the start of an
83 public static DecodedInstruction[] decodeAll(short[] encodedInstructions) {
84 int size = encodedInstructions.length;
85 DecodedInstruction[] decoded = new DecodedInstruction[size];
86 ShortArrayCodeInput in = new ShortArrayCodeInput(encodedInstructions);
89 while (in.hasMore()) {
90 decoded[in.cursor()] = DecodedInstruction.decode(in);
92 } catch (EOFException ex) {
93 throw new AssertionError("shouldn't happen");
100 * Constructs an instance.
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");
108 if (!Opcodes.isValidShape(opcode)) {
109 throw new IllegalArgumentException("invalid opcode");
112 this.format = format;
113 this.opcode = opcode;
115 this.indexType = indexType;
116 this.target = target;
117 this.literal = literal;
120 public final InstructionCodec getFormat() {
124 public final int getOpcode() {
129 * Gets the opcode, as a code unit.
131 public final short getOpcodeUnit() {
132 return (short) opcode;
135 public final int getIndex() {
140 * Gets the index, as a code unit.
142 public final short getIndexUnit() {
143 return (short) index;
146 public final IndexType getIndexType() {
151 * Gets the raw target.
153 public final int getTarget() {
158 * Gets the target as a relative offset from the given address.
160 public final int getTarget(int baseAddress) {
161 return target - baseAddress;
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.
169 public final short getTargetUnit(int baseAddress) {
170 int relativeTarget = getTarget(baseAddress);
172 if (relativeTarget != (short) relativeTarget) {
173 throw new DexException("Target out of range: "
174 + Hex.s4(relativeTarget));
177 return (short) relativeTarget;
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.
185 public final int getTargetByte(int baseAddress) {
186 int relativeTarget = getTarget(baseAddress);
188 if (relativeTarget != (byte) relativeTarget) {
189 throw new DexException("Target out of range: "
190 + Hex.s4(relativeTarget));
193 return relativeTarget & 0xff;
196 public final long getLiteral() {
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.
204 public final int getLiteralInt() {
205 if (literal != (int) target) {
206 throw new DexException("Literal out of range: " + Hex.u8(literal));
209 return (int) literal;
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.
216 public final short getLiteralUnit() {
217 if (literal != (short) target) {
218 throw new DexException("Literal out of range: " + Hex.u8(literal));
221 return (short) literal;
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.
228 public final int getLiteralByte() {
229 if (literal != (byte) target) {
230 throw new DexException("Literal out of range: " + Hex.u8(literal));
233 return (int) literal & 0xff;
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.
240 public final int getLiteralNibble() {
241 if ((literal < -8) || (literal > 7)) {
242 throw new DexException("Literal out of range: " + Hex.u8(literal));
245 return (int) literal & 0xf;
248 public abstract int getRegisterCount();
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.
274 public final short getRegisterCountUnit() {
275 int registerCount = getRegisterCount();
277 if ((registerCount & ~0xffff) != 0) {
278 throw new DexException("Register count out of range: "
279 + Hex.u8(registerCount));
282 return (short) registerCount;
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.
289 public final short getAUnit() {
292 if ((a & ~0xffff) != 0) {
293 throw new DexException("Register A out of range: " + Hex.u8(a));
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.
303 public final short getAByte() {
306 if ((a & ~0xff) != 0) {
307 throw new DexException("Register A out of range: " + Hex.u8(a));
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.
317 public final short getANibble() {
320 if ((a & ~0xf) != 0) {
321 throw new DexException("Register A out of range: " + Hex.u8(a));
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.
331 public final short getBUnit() {
334 if ((b & ~0xffff) != 0) {
335 throw new DexException("Register B out of range: " + Hex.u8(b));
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.
345 public final short getBByte() {
348 if ((b & ~0xff) != 0) {
349 throw new DexException("Register B out of range: " + Hex.u8(b));
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.
359 public final short getBNibble() {
362 if ((b & ~0xf) != 0) {
363 throw new DexException("Register B out of range: " + Hex.u8(b));
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.
373 public final short getCUnit() {
376 if ((c & ~0xffff) != 0) {
377 throw new DexException("Register C out of range: " + Hex.u8(c));
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.
387 public final short getCByte() {
390 if ((c & ~0xff) != 0) {
391 throw new DexException("Register C out of range: " + Hex.u8(c));
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.
401 public final short getCNibble() {
404 if ((c & ~0xf) != 0) {
405 throw new DexException("Register C out of range: " + Hex.u8(c));
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.
415 public final short getDUnit() {
418 if ((d & ~0xffff) != 0) {
419 throw new DexException("Register D out of range: " + Hex.u8(d));
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.
429 public final short getDByte() {
432 if ((d & ~0xff) != 0) {
433 throw new DexException("Register D out of range: " + Hex.u8(d));
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.
443 public final short getDNibble() {
446 if ((d & ~0xf) != 0) {
447 throw new DexException("Register D out of range: " + Hex.u8(d));
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.
457 public final short getENibble() {
460 if ((e & ~0xf) != 0) {
461 throw new DexException("Register E out of range: " + Hex.u8(e));
468 * Encodes this instance to the given output.
470 public final void encode(CodeOutput out) {
471 format.encode(this, out);
475 * Returns an instance just like this one, except with the index replaced
476 * with the given one.
478 public abstract DecodedInstruction withIndex(int newIndex);