1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ART_SRC_DEX_INSTRUCTION_H_
#define ART_SRC_DEX_INSTRUCTION_H_
#include "globals.h"
#include "logging.h"
#include "macros.h"
namespace art {
class DexFile;
class Instruction {
public:
// NOP-encoded switch-statement signatures.
enum {
kPackedSwitchSignature = 0x0100,
kSparseSwitchSignature = 0x0200,
kArrayDataSignature = 0x0300
};
enum Code {
#define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a, v) cname = opcode,
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
#undef DEX_INSTRUCTION_LIST
#undef INSTRUCTION_ENUM
};
enum InstructionFormat {
k10x, // op
k12x, // op vA, vB
k11n, // op vA, #+B
k11x, // op vAA
k10t, // op +AA
k20bc, // op AA, kind@BBBB
k20t, // op +AAAA
k22x, // op vAA, vBBBB
k21t, // op vAA, +BBBB
k21s, // op vAA, #+BBBB
k21h, // op vAA, #+BBBB00000[00000000]
k21c, // op vAA, thing@BBBB
k23x, // op vAA, vBB, vCC
k22b, // op vAA, vBB, #+CC
k22t, // op vA, vB, +CCCC
k22s, // op vA, vB, #+CCCC
k22c, // op vA, vB, thing@CCCC
k32x, // op vAAAA, vBBBB
k30t, // op +AAAAAAAA
k31t, // op vAA, +BBBBBBBB
k31i, // op vAA, #+BBBBBBBB
k31c, // op vAA, thing@BBBBBBBB
k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG)
k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
k51l, // op vAA, #+BBBBBBBBBBBBBBBB
};
enum Flags {
kBranch = 0x01, // conditional or unconditional branch
kContinue = 0x02, // flow can continue to next statement
kSwitch = 0x04, // switch statement
kThrow = 0x08, // could cause an exception to be thrown
kReturn = 0x10, // returns, no additional statements
kInvoke = 0x20, // a flavor of invoke
// TODO: kUnconditional
};
enum VerifyFlag {
kVerifyNone = 0x00000,
kVerifyRegA = 0x00001,
kVerifyRegAWide = 0x00002,
kVerifyRegB = 0x00004,
kVerifyRegBField = 0x00008,
kVerifyRegBMethod = 0x00010,
kVerifyRegBNewInstance = 0x00020,
kVerifyRegBString = 0x00040,
kVerifyRegBType = 0x00080,
kVerifyRegBWide = 0x00100,
kVerifyRegC = 0x00200,
kVerifyRegCField = 0x00400,
kVerifyRegCNewArray = 0x00800,
kVerifyRegCType = 0x01000,
kVerifyRegCWide = 0x02000,
kVerifyArrayData = 0x04000,
kVerifyBranchTarget = 0x08000,
kVerifySwitchTargets = 0x10000,
kVerifyVarArg = 0x20000,
kVerifyVarArgRange = 0x40000,
kVerifyError = 0x80000,
};
/*
* Holds the contents of a decoded instruction.
*/
struct DecodedInstruction {
uint32_t vA_;
uint32_t vB_;
uint64_t vB_wide_; /* for kFmt51l */
uint32_t vC_;
uint32_t arg_[5]; /* vC/D/E/F/G in invoke or filled-new-array */
Code opcode_;
explicit DecodedInstruction(const Instruction* inst) {
inst->Decode(vA_, vB_, vB_wide_, vC_, arg_);
opcode_ = inst->Opcode();
}
};
// Decodes this instruction, populating its arguments.
void Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const;
// Returns the size in 2 byte code units, for this instruction.
size_t SizeInCodeUnits() const;
// Returns a pointer to the next instruction in the stream.
const Instruction* Next() const;
// Name of the instruction.
const char* Name() const {
return kInstructionNames[Opcode()];
}
// Returns the opcode field of the instruction.
Code Opcode() const;
// Reads an instruction out of the stream at the specified address.
static const Instruction* At(const uint16_t* code) {
CHECK(code != NULL);
return reinterpret_cast<const Instruction*>(code);
}
// Returns the format of the current instruction.
InstructionFormat Format() const {
return kInstructionFormats[Opcode()];
}
// Returns the flags for the current instruction.
int Flag() const {
return kInstructionFlags[Opcode()];
}
// Returns true if this instruction is a branch.
bool IsBranch() const {
return (kInstructionFlags[Opcode()] & kBranch) != 0;
}
// Returns true if this instruction is a switch.
bool IsSwitch() const {
return (kInstructionFlags[Opcode()] & kSwitch) != 0;
}
// Returns true if this instruction can throw.
bool IsThrow() const {
return (kInstructionFlags[Opcode()] & kThrow) != 0;
}
// Determine if the instruction is any of 'return' instructions.
bool IsReturn() const {
return (kInstructionFlags[Opcode()] & kReturn) != 0;
}
// Determine if this instruction ends execution of its basic block.
bool IsBasicBlockEnd() const {
return IsBranch() || IsReturn() || Opcode() == THROW;
}
// Determine if this instruction is an invoke.
bool IsInvoke() const {
return (kInstructionFlags[Opcode()] & kInvoke) != 0;
}
int GetVerifyTypeArgumentA() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegA | kVerifyRegAWide));
}
int GetVerifyTypeArgumentB() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | kVerifyRegBMethod |
kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | kVerifyRegBWide));
}
int GetVerifyTypeArgumentC() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField |
kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
}
int GetVerifyExtraFlags() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget |
kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
}
// Dump decoded version of instruction
std::string DumpString(const DexFile*) const;
// Dump code_units worth of this instruction, padding to code_units for shorter instructions
std::string DumpHex(size_t code_units) const;
private:
static const char* const kInstructionNames[];
static InstructionFormat const kInstructionFormats[];
static int const kInstructionFlags[];
static int const kInstructionVerifyFlags[];
DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
};
std::ostream& operator<<(std::ostream& os, const Instruction& rhs);
} // namespace art
#endif // ART_SRC_DEX_INSTRUCTION_H_
|