blob: f94ce31c4e85ca49f9f71faca43bd9996137ab1d [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 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 */
Andy McFadden3a1aedb2009-05-07 13:30:23 -070016
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080017/*
18 * Dalvik instruction utility functions.
19 */
20#ifndef _LIBDEX_INSTRUTILS
21#define _LIBDEX_INSTRUTILS
22
23#include "DexFile.h"
24#include "OpCode.h"
25
26/*
27 * Dalvik-defined instruction formats.
28 *
29 * (This defines InstructionFormat as an unsigned char to reduce the size
30 * of the table. This isn't necessary with some compilers, which use an
31 * integer width appropriate for the number of enum values.)
Carl Shapirode750892010-06-08 16:37:12 -070032 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080033 * If you add or delete a format, you have to change some or all of:
34 * - this enum
35 * - the switch inside dexDecodeInstruction() in InstrUtils.c
36 * - the switch inside dumpInstruction() in DexDump.c
Dan Bornstein44a38f42010-11-10 17:34:32 -080037 * - the switch inside dvmCompilerMIR2LIR() in CodegenDriver.c
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080038 */
39typedef unsigned char InstructionFormat;
40enum InstructionFormat {
41 kFmtUnknown = 0,
42 kFmt10x, // op
43 kFmt12x, // op vA, vB
44 kFmt11n, // op vA, #+B
45 kFmt11x, // op vAA
46 kFmt10t, // op +AA
Andy McFaddend3250112010-11-03 14:32:42 -070047 kFmt20bc, // [opt] op AA, thing@BBBB
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080048 kFmt20t, // op +AAAA
49 kFmt22x, // op vAA, vBBBB
50 kFmt21t, // op vAA, +BBBB
51 kFmt21s, // op vAA, #+BBBB
52 kFmt21h, // op vAA, #+BBBB00000[00000000]
53 kFmt21c, // op vAA, thing@BBBB
54 kFmt23x, // op vAA, vBB, vCC
55 kFmt22b, // op vAA, vBB, #+CC
56 kFmt22t, // op vA, vB, +CCCC
57 kFmt22s, // op vA, vB, #+CCCC
58 kFmt22c, // op vA, vB, thing@CCCC
59 kFmt22cs, // [opt] op vA, vB, field offset CCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060 kFmt30t, // op +AAAAAAAA
Andy McFaddend3250112010-11-03 14:32:42 -070061 kFmt32x, // op vAAAA, vBBBB
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080062 kFmt31i, // op vAA, #+BBBBBBBB
Andy McFaddend3250112010-11-03 14:32:42 -070063 kFmt31t, // op vAA, +BBBBBBBB
64 kFmt31c, // op vAA, string@BBBBBBBB
Dan Bornstein7b3e9b02010-11-09 17:15:10 -080065 kFmt35c, // op {vC,vD,vE,vF,vG}, thing@BBBB
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080066 kFmt35ms, // [opt] invoke-virtual+super
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080067 kFmt3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
68 kFmt3rms, // [opt] invoke-virtual+super/range
Andy McFaddend3250112010-11-03 14:32:42 -070069 kFmt51l, // op vAA, #+BBBBBBBBBBBBBBBB
Dan Bornstein7b3e9b02010-11-09 17:15:10 -080070 kFmt35mi, // [opt] inline invoke
71 kFmt3rmi, // [opt] inline invoke/range
72 /* coming soon:
73 kFmt33x, // exop vAA, vBB, vCCCC
74 kFmt32s, // exop vAA, vBB, #+CCCC
75 kFmt41c, // exop vAAAA, thing@BBBBBBBB
Dan Bornstein44a38f42010-11-10 17:34:32 -080076 kFmt52c, // exop vAAAA, vBBBB, thing@CCCCCCCC
Dan Bornstein7b3e9b02010-11-09 17:15:10 -080077 kFmt5rc, // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB
78 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080079};
80
81/*
Dan Bornstein44a38f42010-11-10 17:34:32 -080082 * Different kinds of indexed reference, for formats that include such an
83 * indexed reference (e.g., 21c and 35c)
84 */
85typedef unsigned char InstructionIndexType;
86enum InstructionIndexType {
87 kIndexUnknown = 0,
88 kIndexNone, // has no index
89 kIndexVaries, // "It depends." Used for throw-verification-error
90 kIndexClassRef, // class reference index
91 kIndexStringRef, // string reference index
92 kIndexMethodRef, // method reference index
93 kIndexFieldRef, // field reference index
94 kIndexInlineMethod, // inline method index (for inline linked methods)
95 kIndexVtableOffset, // vtable offset (for static linked methods)
96 kIndexFieldOffset // field offset (for static linked fields)
97};
98
99/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800100 * Holds the contents of a decoded instruction.
101 */
102typedef struct DecodedInstruction {
103 u4 vA;
104 u4 vB;
105 u8 vB_wide; /* for kFmt51l */
106 u4 vC;
107 u4 arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */
108 OpCode opCode;
Dan Bornstein44a38f42010-11-10 17:34:32 -0800109 InstructionIndexType indexType;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110} DecodedInstruction;
111
112/*
113 * Instruction width, a value in the range -3 to 5.
114 */
115typedef signed char InstructionWidth;
116
117/*
Andy McFadden2e1ee502010-03-24 13:25:53 -0700118 * Instruction flags, used by the verifier and JIT to determine where
119 * control can flow to next. Expected to fit in 8 bits.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800120 */
121typedef unsigned char InstructionFlags;
122enum InstructionFlags {
123 kInstrCanBranch = 1, // conditional or unconditional branch
124 kInstrCanContinue = 1 << 1, // flow can continue to next statement
125 kInstrCanSwitch = 1 << 2, // switch statement
126 kInstrCanThrow = 1 << 3, // could cause an exception to be thrown
127 kInstrCanReturn = 1 << 4, // returns, no additional statements
Ben Chengba4fc8b2009-06-01 13:00:29 -0700128 kInstrInvoke = 1 << 5, // a flavor of invoke
129 kInstrUnconditional = 1 << 6, // unconditional branch
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800130};
131
Dan Bornstein44a38f42010-11-10 17:34:32 -0800132/*
133 * Struct that includes a pointer to each of the instruction information
134 * tables.
135 */
136typedef struct InstructionInfoTables {
137 InstructionFormat* formats;
138 InstructionIndexType* indexTypes;
139 InstructionFlags* flags;
140 InstructionWidth* widths;
141} InstructionInfoTables;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800142
143/*
144 * Allocate and populate a 256-element array with instruction widths. A
145 * width of zero means the entry does not exist.
146 */
147InstructionWidth* dexCreateInstrWidthTable(void);
148
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800149/*
150 * Return the width of the specified instruction, or 0 if not defined.
151 */
Andy McFadden228a6b02010-05-04 15:02:32 -0700152DEX_INLINE size_t dexGetInstrWidthAbs(const InstructionWidth* widths,
153 OpCode opCode)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800154{
155 //assert(/*opCode >= 0 &&*/ opCode < kNumDalvikInstructions);
156
Andy McFadden861b3382010-03-05 15:58:31 -0800157 int val = widths[opCode];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800158 if (val < 0)
159 val = -val;
160 /* XXX - the no-compare trick may be a cycle slower on ARM */
161 return val;
162}
163
164/*
165 * Return the width of the specified instruction, or 0 if not defined. Also
166 * works for special OP_NOP entries, including switch statement data tables
167 * and array data.
168 */
Andy McFadden228a6b02010-05-04 15:02:32 -0700169size_t dexGetInstrOrTableWidthAbs(const InstructionWidth* widths,
170 const u2* insns);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800171
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800172/*
173 * Allocate and populate a 256-element array with instruction flags.
174 */
175InstructionFlags* dexCreateInstrFlagsTable(void);
176
177/*
178 * Returns the flags for the specified opcode.
179 */
180DEX_INLINE int dexGetInstrFlags(const InstructionFlags* flags, OpCode opCode)
181{
182 //assert(/*opCode >= 0 &&*/ opCode < kNumDalvikInstructions);
183 return flags[opCode];
184}
185
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800186/*
187 * Allocate and populate a 256-element array with instruction formats.
188 */
189InstructionFormat* dexCreateInstrFormatTable(void);
190
191/*
192 * Return the instruction format for the specified opcode.
193 */
194DEX_INLINE InstructionFormat dexGetInstrFormat(const InstructionFormat* fmts,
195 OpCode opCode)
196{
197 //assert(/*opCode >= 0 &&*/ opCode < kNumDalvikInstructions);
198 return fmts[opCode];
199}
200
201/*
Dan Bornstein44a38f42010-11-10 17:34:32 -0800202 * Allocate and populate an array with index types for all instructions.
203 * Used in conjunction with dexDecodeInstruction.
204 */
205InstructionIndexType* dexCreateInstrIndexTypeTable(void);
206
207/*
208 * Return the instruction index type for the specified opcode.
209 */
210DEX_INLINE InstructionIndexType dexGetInstrIndexType(
211 const InstructionIndexType* types, OpCode opCode)
212{
213 //assert(/*opCode >= 0 &&*/ opCode < kNumDalvikInstructions);
214 return types[opCode];
215}
216
217/*
218 * Construct all of the instruction info tables, storing references to
219 * them into the given struct. This returns 0 on success or non-zero on
220 * failure. If this fails, then no net allocation will have occurred.
221 */
222int dexCreateInstructionInfoTables(InstructionInfoTables* info);
223
224/*
225 * Free up the tables referred to by the given instruction info struct.
226 */
227void dexFreeInstructionInfoTables(InstructionInfoTables* info);
228
229/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800230 * Decode the instruction pointed to by "insns".
231 */
Dan Bornstein44a38f42010-11-10 17:34:32 -0800232void dexDecodeInstruction(const InstructionInfoTables* info, const u2* insns,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800233 DecodedInstruction* pDec);
234
235#endif /*_LIBDEX_INSTRUTILS*/