blob: ff816594c024705117dc0c2c674cb918d467f5d3 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
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 */
Carl Shapiro12eb78e2011-06-24 14:51:06 -070016
17#ifndef ART_SRC_DEX_INSTRUCTION_H_
18#define ART_SRC_DEX_INSTRUCTION_H_
19
Elliott Hughes07ed66b2012-12-12 18:34:25 -080020#include "base/logging.h"
Elliott Hughes76160052012-12-12 16:31:20 -080021#include "base/macros.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070022#include "globals.h"
Carl Shapiro12eb78e2011-06-24 14:51:06 -070023
Sebastien Hertz807a2562013-04-15 09:33:39 +020024typedef uint8_t uint4_t;
25typedef int8_t int4_t;
26
Carl Shapiro12eb78e2011-06-24 14:51:06 -070027namespace art {
28
Ian Rogersd81871c2011-10-03 13:57:23 -070029class DexFile;
30
Elliott Hughesadb8c672012-03-06 16:49:32 -080031enum {
32 kNumPackedOpcodes = 0x100
33};
34
Carl Shapiro12eb78e2011-06-24 14:51:06 -070035class Instruction {
36 public:
Carl Shapiroe4c1ce42011-07-09 02:31:57 -070037 // NOP-encoded switch-statement signatures.
38 enum {
39 kPackedSwitchSignature = 0x0100,
40 kSparseSwitchSignature = 0x0200,
Elliott Hughesadb8c672012-03-06 16:49:32 -080041 kArrayDataSignature = 0x0300,
Carl Shapiroe4c1ce42011-07-09 02:31:57 -070042 };
43
Ian Rogersdf1ce912012-11-27 17:07:11 -080044 struct PACKED(4) PackedSwitchPayload {
Logan Chien19c350a2012-05-01 19:21:32 +080045 const uint16_t ident;
46 const uint16_t case_count;
47 const int32_t first_key;
48 const int32_t targets[];
Dragos Sbirlea39f99272013-06-25 13:17:36 -070049
Logan Chien19c350a2012-05-01 19:21:32 +080050 private:
51 DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload);
52 };
53
Ian Rogersdf1ce912012-11-27 17:07:11 -080054 struct PACKED(4) SparseSwitchPayload {
Logan Chien19c350a2012-05-01 19:21:32 +080055 const uint16_t ident;
56 const uint16_t case_count;
57 const int32_t keys_and_targets[];
58
59 public:
60 const int32_t* GetKeys() const {
61 return keys_and_targets;
62 }
63
64 const int32_t* GetTargets() const {
65 return keys_and_targets + case_count;
66 }
67
68 private:
69 DISALLOW_COPY_AND_ASSIGN(SparseSwitchPayload);
70 };
71
Ian Rogersdf1ce912012-11-27 17:07:11 -080072 struct PACKED(4) ArrayDataPayload {
Logan Chien19c350a2012-05-01 19:21:32 +080073 const uint16_t ident;
74 const uint16_t element_width;
75 const uint32_t element_count;
76 const uint8_t data[];
Dragos Sbirlea39f99272013-06-25 13:17:36 -070077
Logan Chien19c350a2012-05-01 19:21:32 +080078 private:
79 DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload);
80 };
81
Ian Rogersa75a0132012-09-28 11:41:42 -070082 // TODO: the code layout below is deliberate to avoid this enum being picked up by
83 // generate-operator-out.py.
84 enum Code
85 {
jeffhaoba5ebb92011-08-25 17:24:37 -070086#define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a, v) cname = opcode,
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070087#include "dex_instruction_list.h"
Carl Shapiro12eb78e2011-06-24 14:51:06 -070088 DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
Carl Shapirod84f49c2011-06-29 00:27:46 -070089#undef DEX_INSTRUCTION_LIST
Carl Shapiro12eb78e2011-06-24 14:51:06 -070090#undef INSTRUCTION_ENUM
Ian Rogersa75a0132012-09-28 11:41:42 -070091 } ;
Carl Shapiro12eb78e2011-06-24 14:51:06 -070092
Elliott Hughesadb8c672012-03-06 16:49:32 -080093 enum Format {
Carl Shapiroe4c1ce42011-07-09 02:31:57 -070094 k10x, // op
95 k12x, // op vA, vB
96 k11n, // op vA, #+B
97 k11x, // op vAA
98 k10t, // op +AA
99 k20t, // op +AAAA
100 k22x, // op vAA, vBBBB
101 k21t, // op vAA, +BBBB
102 k21s, // op vAA, #+BBBB
103 k21h, // op vAA, #+BBBB00000[00000000]
104 k21c, // op vAA, thing@BBBB
105 k23x, // op vAA, vBB, vCC
106 k22b, // op vAA, vBB, #+CC
107 k22t, // op vA, vB, +CCCC
108 k22s, // op vA, vB, #+CCCC
109 k22c, // op vA, vB, thing@CCCC
110 k32x, // op vAAAA, vBBBB
111 k30t, // op +AAAAAAAA
112 k31t, // op vAA, +BBBBBBBB
113 k31i, // op vAA, #+BBBBBBBB
114 k31c, // op vAA, thing@BBBBBBBB
115 k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG)
116 k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
117 k51l, // op vAA, #+BBBBBBBBBBBBBBBB
118 };
119
120 enum Flags {
121 kBranch = 0x01, // conditional or unconditional branch
122 kContinue = 0x02, // flow can continue to next statement
123 kSwitch = 0x04, // switch statement
124 kThrow = 0x08, // could cause an exception to be thrown
125 kReturn = 0x10, // returns, no additional statements
126 kInvoke = 0x20, // a flavor of invoke
TDYa127526643e2012-05-26 01:01:48 -0700127 kUnconditional = 0x40, // unconditional branch
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700128 };
129
jeffhaoba5ebb92011-08-25 17:24:37 -0700130 enum VerifyFlag {
131 kVerifyNone = 0x00000,
132 kVerifyRegA = 0x00001,
133 kVerifyRegAWide = 0x00002,
134 kVerifyRegB = 0x00004,
135 kVerifyRegBField = 0x00008,
136 kVerifyRegBMethod = 0x00010,
137 kVerifyRegBNewInstance = 0x00020,
138 kVerifyRegBString = 0x00040,
139 kVerifyRegBType = 0x00080,
140 kVerifyRegBWide = 0x00100,
141 kVerifyRegC = 0x00200,
142 kVerifyRegCField = 0x00400,
143 kVerifyRegCNewArray = 0x00800,
144 kVerifyRegCType = 0x01000,
145 kVerifyRegCWide = 0x02000,
146 kVerifyArrayData = 0x04000,
147 kVerifyBranchTarget = 0x08000,
148 kVerifySwitchTargets = 0x10000,
149 kVerifyVarArg = 0x20000,
150 kVerifyVarArgRange = 0x40000,
151 kVerifyError = 0x80000,
152 };
153
154 // Decodes this instruction, populating its arguments.
155 void Decode(uint32_t &vA, uint32_t &vB, uint64_t &vB_wide, uint32_t &vC, uint32_t arg[]) const;
156
Elliott Hughesadb8c672012-03-06 16:49:32 -0800157 // Returns the size (in 2 byte code units) of this instruction.
Ian Rogersa75a0132012-09-28 11:41:42 -0700158 size_t SizeInCodeUnits() const {
159 int result = kInstructionSizeInCodeUnits[Opcode()];
160 if (UNLIKELY(result < 0)) {
161 return SizeInCodeUnitsComplexOpcode();
162 } else {
163 return static_cast<size_t>(result);
164 }
165 }
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700166
Sebastien Hertz92c607f2013-06-04 16:18:52 +0200167 // Reads an instruction out of the stream at the specified address.
168 static const Instruction* At(const uint16_t* code) {
169 DCHECK(code != NULL);
170 return reinterpret_cast<const Instruction*>(code);
171 }
172
173 // Reads an instruction out of the stream from the current address plus an offset.
174 const Instruction* RelativeAt(int32_t offset) const {
175 return At(reinterpret_cast<const uint16_t*>(this) + offset);
176 }
177
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700178 // Returns a pointer to the next instruction in the stream.
Ian Rogersa75a0132012-09-28 11:41:42 -0700179 const Instruction* Next() const {
Sebastien Hertz92c607f2013-06-04 16:18:52 +0200180 return RelativeAt(SizeInCodeUnits());
Ian Rogersa75a0132012-09-28 11:41:42 -0700181 }
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700182
Jeff Hao9cec2472013-05-14 18:17:06 -0700183 // Returns a pointer to the instruction after this 1xx instruction in the stream.
184 const Instruction* Next_1xx() const {
185 DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t);
Sebastien Hertz92c607f2013-06-04 16:18:52 +0200186 return RelativeAt(1);
Jeff Hao9cec2472013-05-14 18:17:06 -0700187 }
188
189 // Returns a pointer to the instruction after this 2xx instruction in the stream.
190 const Instruction* Next_2xx() const {
191 DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c);
Sebastien Hertz92c607f2013-06-04 16:18:52 +0200192 return RelativeAt(2);
Jeff Hao9cec2472013-05-14 18:17:06 -0700193 }
194
195 // Returns a pointer to the instruction after this 3xx instruction in the stream.
196 const Instruction* Next_3xx() const {
197 DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc);
Sebastien Hertz92c607f2013-06-04 16:18:52 +0200198 return RelativeAt(3);
Jeff Hao9cec2472013-05-14 18:17:06 -0700199 }
200
201 // Returns a pointer to the instruction after this 51l instruction in the stream.
Sebastien Hertz92c607f2013-06-04 16:18:52 +0200202 const Instruction* Next_51l() const {
203 DCHECK(FormatOf(Opcode()) == k51l);
204 return RelativeAt(5);
205 }
Jeff Hao9cec2472013-05-14 18:17:06 -0700206
Elliott Hughesadb8c672012-03-06 16:49:32 -0800207 // Returns the name of this instruction's opcode.
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700208 const char* Name() const {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800209 return Instruction::Name(Opcode());
210 }
211
212 // Returns the name of the given opcode.
213 static const char* Name(Code opcode) {
214 return kInstructionNames[opcode];
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700215 }
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700216
Sebastien Hertz807a2562013-04-15 09:33:39 +0200217 // VRegA
Dragos Sbirlea8cc51622013-06-21 09:20:34 -0700218 bool HasVRegA() const;
Dragos Sbirlead25de7a2013-06-21 09:20:34 -0700219 int32_t VRegA() const;
Sebastien Hertz807a2562013-04-15 09:33:39 +0200220 int8_t VRegA_10t() const;
Sebastien Hertz5243e912013-05-21 10:55:07 +0200221 uint8_t VRegA_10x() const;
Sebastien Hertz807a2562013-04-15 09:33:39 +0200222 uint4_t VRegA_11n() const;
223 uint8_t VRegA_11x() const;
224 uint4_t VRegA_12x() const;
225 int16_t VRegA_20t() const;
226 uint8_t VRegA_21c() const;
227 uint8_t VRegA_21h() const;
228 uint8_t VRegA_21s() const;
229 uint8_t VRegA_21t() const;
230 uint8_t VRegA_22b() const;
231 uint4_t VRegA_22c() const;
232 uint4_t VRegA_22s() const;
233 uint4_t VRegA_22t() const;
234 uint8_t VRegA_22x() const;
235 uint8_t VRegA_23x() const;
236 int32_t VRegA_30t() const;
237 uint8_t VRegA_31c() const;
238 uint8_t VRegA_31i() const;
239 uint8_t VRegA_31t() const;
240 uint16_t VRegA_32x() const;
241 uint4_t VRegA_35c() const;
242 uint8_t VRegA_3rc() const;
243 uint8_t VRegA_51l() const;
244
245 // VRegB
Dragos Sbirlea8cc51622013-06-21 09:20:34 -0700246 bool HasVRegB() const;
Dragos Sbirlea39f99272013-06-25 13:17:36 -0700247 int32_t VRegB() const;
Sebastien Hertz807a2562013-04-15 09:33:39 +0200248 int4_t VRegB_11n() const;
249 uint4_t VRegB_12x() const;
250 uint16_t VRegB_21c() const;
251 uint16_t VRegB_21h() const;
252 int16_t VRegB_21s() const;
253 int16_t VRegB_21t() const;
254 uint8_t VRegB_22b() const;
255 uint4_t VRegB_22c() const;
256 uint4_t VRegB_22s() const;
257 uint4_t VRegB_22t() const;
258 uint16_t VRegB_22x() const;
259 uint8_t VRegB_23x() const;
260 uint32_t VRegB_31c() const;
261 int32_t VRegB_31i() const;
262 int32_t VRegB_31t() const;
263 uint16_t VRegB_32x() const;
264 uint16_t VRegB_35c() const;
265 uint16_t VRegB_3rc() const;
Dragos Sbirlea39f99272013-06-25 13:17:36 -0700266 uint64_t VRegB_51l() const; // vB_wide
Sebastien Hertz807a2562013-04-15 09:33:39 +0200267
268 // VRegC
Dragos Sbirlea8cc51622013-06-21 09:20:34 -0700269 bool HasVRegC() const;
Dragos Sbirlea39f99272013-06-25 13:17:36 -0700270 int32_t VRegC() const;
Sebastien Hertz807a2562013-04-15 09:33:39 +0200271 int8_t VRegC_22b() const;
272 uint16_t VRegC_22c() const;
273 int16_t VRegC_22s() const;
274 int16_t VRegC_22t() const;
275 uint8_t VRegC_23x() const;
276 uint4_t VRegC_35c() const;
277 uint16_t VRegC_3rc() const;
278
279 // Fills the given array with the 'arg' array of the instruction.
280 void GetArgs(uint32_t args[5]) const;
281
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700282 // Returns the opcode field of the instruction.
Ian Rogersa75a0132012-09-28 11:41:42 -0700283 Code Opcode() const {
284 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
285 int opcode = *insns & 0xFF;
286 return static_cast<Code>(opcode);
287 }
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700288
Sebastien Hertz2d6ba512013-05-17 11:31:37 +0200289 void SetOpcode(Code opcode) {
290 DCHECK_LT(static_cast<uint16_t>(opcode), 256u);
291 uint16_t* insns = reinterpret_cast<uint16_t*>(this);
292 insns[0] = (insns[0] & 0xff00) | static_cast<uint16_t>(opcode);
293 }
294
Sebastien Hertz543959c2013-07-03 12:00:19 +0200295 void SetVRegA_10x(uint8_t val) {
296 DCHECK(FormatOf(Opcode()) == k10x);
297 uint16_t* insns = reinterpret_cast<uint16_t*>(this);
298 insns[0] = (val << 8) | (insns[0] & 0x00ff);
299 }
300
Sebastien Hertz2d6ba512013-05-17 11:31:37 +0200301 void SetVRegB_3rc(uint16_t val) {
302 DCHECK(FormatOf(Opcode()) == k3rc);
303 uint16_t* insns = reinterpret_cast<uint16_t*>(this);
304 insns[1] = val;
305 }
306
307 void SetVRegB_35c(uint16_t val) {
308 DCHECK(FormatOf(Opcode()) == k35c);
309 uint16_t* insns = reinterpret_cast<uint16_t*>(this);
310 insns[1] = val;
311 }
312
313 void SetVRegC_22c(uint16_t val) {
314 DCHECK(FormatOf(Opcode()) == k22c);
315 uint16_t* insns = reinterpret_cast<uint16_t*>(this);
316 insns[1] = val;
317 }
318
Elliott Hughesadb8c672012-03-06 16:49:32 -0800319 // Returns the format of the given opcode.
320 static Format FormatOf(Code opcode) {
321 return kInstructionFormats[opcode];
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700322 }
323
Elliott Hughesadb8c672012-03-06 16:49:32 -0800324 // Returns the flags for the given opcode.
Ian Rogersa75a0132012-09-28 11:41:42 -0700325 static int FlagsOf(Code opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800326 return kInstructionFlags[opcode];
jeffhaobdb76512011-09-07 11:43:16 -0700327 }
328
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700329 // Returns true if this instruction is a branch.
330 bool IsBranch() const {
331 return (kInstructionFlags[Opcode()] & kBranch) != 0;
332 }
333
TDYa127526643e2012-05-26 01:01:48 -0700334 // Returns true if this instruction is a unconditional branch.
335 bool IsUnconditional() const {
336 return (kInstructionFlags[Opcode()] & kUnconditional) != 0;
337 }
338
Dragos Sbirlea39f99272013-06-25 13:17:36 -0700339 // Returns the branch offset if this instruction is a branch.
340 int32_t GetTargetOffset() const;
341
342 // Returns true if the instruction allows control flow to go to the following instruction.
343 bool CanFlowThrough() const;
344
jeffhaoba5ebb92011-08-25 17:24:37 -0700345 // Returns true if this instruction is a switch.
346 bool IsSwitch() const {
347 return (kInstructionFlags[Opcode()] & kSwitch) != 0;
348 }
349
350 // Returns true if this instruction can throw.
351 bool IsThrow() const {
352 return (kInstructionFlags[Opcode()] & kThrow) != 0;
353 }
354
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700355 // Determine if the instruction is any of 'return' instructions.
356 bool IsReturn() const {
357 return (kInstructionFlags[Opcode()] & kReturn) != 0;
358 }
359
360 // Determine if this instruction ends execution of its basic block.
361 bool IsBasicBlockEnd() const {
362 return IsBranch() || IsReturn() || Opcode() == THROW;
363 }
364
365 // Determine if this instruction is an invoke.
366 bool IsInvoke() const {
367 return (kInstructionFlags[Opcode()] & kInvoke) != 0;
368 }
369
jeffhaoba5ebb92011-08-25 17:24:37 -0700370 int GetVerifyTypeArgumentA() const {
371 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegA | kVerifyRegAWide));
372 }
373
374 int GetVerifyTypeArgumentB() const {
375 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | kVerifyRegBMethod |
376 kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | kVerifyRegBWide));
377 }
378
379 int GetVerifyTypeArgumentC() const {
380 return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField |
jeffhao3bb32462012-02-01 16:12:27 -0800381 kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
jeffhaoba5ebb92011-08-25 17:24:37 -0700382 }
383
384 int GetVerifyExtraFlags() const {
385 return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget |
386 kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgRange | kVerifyError));
387 }
388
Ian Rogers2fa6b2e2012-10-17 00:10:17 -0700389 // Get the dex PC of this instruction as a offset in code units from the beginning of insns.
390 uint32_t GetDexPc(const uint16_t* insns) const {
391 return (reinterpret_cast<const uint16_t*>(this) - insns);
392 }
393
Ian Rogersd81871c2011-10-03 13:57:23 -0700394 // Dump decoded version of instruction
Ian Rogers2c8a8572011-10-24 17:11:36 -0700395 std::string DumpString(const DexFile*) const;
396
397 // Dump code_units worth of this instruction, padding to code_units for shorter instructions
398 std::string DumpHex(size_t code_units) const;
Ian Rogersd81871c2011-10-03 13:57:23 -0700399
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700400 private:
Ian Rogersa75a0132012-09-28 11:41:42 -0700401 size_t SizeInCodeUnitsComplexOpcode() const;
402
Sebastien Hertz807a2562013-04-15 09:33:39 +0200403 uint16_t Fetch16(size_t offset) const {
404 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
405 return insns[offset];
406 }
407
408 uint32_t Fetch32(size_t offset) const {
409 return (Fetch16(offset) | ((uint32_t) Fetch16(offset + 1) << 16));
410 }
411
412 uint4_t InstA() const {
413 return static_cast<uint4_t>((Fetch16(0) >> 8) & 0x0f);
414 }
415
416 uint4_t InstB() const {
417 return static_cast<uint4_t>(Fetch16(0) >> 12);
418 }
419
420 uint8_t InstAA() const {
421 return static_cast<uint8_t>(Fetch16(0) >> 8);
422 }
423
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700424 static const char* const kInstructionNames[];
Elliott Hughesadb8c672012-03-06 16:49:32 -0800425 static Format const kInstructionFormats[];
Carl Shapiroe4c1ce42011-07-09 02:31:57 -0700426 static int const kInstructionFlags[];
jeffhaoba5ebb92011-08-25 17:24:37 -0700427 static int const kInstructionVerifyFlags[];
Ian Rogersa75a0132012-09-28 11:41:42 -0700428 static int const kInstructionSizeInCodeUnits[];
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700429 DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
430};
Ian Rogersa75a0132012-09-28 11:41:42 -0700431std::ostream& operator<<(std::ostream& os, const Instruction::Code& code);
432std::ostream& operator<<(std::ostream& os, const Instruction::Format& format);
433std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
434std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800435
436/*
437 * Holds the contents of a decoded instruction.
438 */
439struct DecodedInstruction {
440 uint32_t vA;
441 uint32_t vB;
442 uint64_t vB_wide; /* for k51l */
443 uint32_t vC;
444 uint32_t arg[5]; /* vC/D/E/F/G in invoke or filled-new-array */
445 Instruction::Code opcode;
446
Ian Rogersa75a0132012-09-28 11:41:42 -0700447 explicit DecodedInstruction(const Instruction* inst) {
448 inst->Decode(vA, vB, vB_wide, vC, arg);
449 opcode = inst->Opcode();
450 }
Elliott Hughesadb8c672012-03-06 16:49:32 -0800451};
Carl Shapiro12eb78e2011-06-24 14:51:06 -0700452
453} // namespace art
454
455#endif // ART_SRC_DEX_INSTRUCTION_H_