summaryrefslogtreecommitdiffstats
path: root/runtime/dex_instruction_utils.h
blob: f892f980a18a2989ce0d9a3766e76bc8593bfa7c (plain)
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
224
225
226
227
228
229
230
231
232
233
/*
 * Copyright (C) 2014 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_RUNTIME_DEX_INSTRUCTION_UTILS_H_
#define ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_

#include "dex_instruction.h"

namespace art {

// Dex invoke type corresponds to the ordering of INVOKE instructions;
// this order is the same for range and non-range invokes.
enum DexInvokeType : uint8_t {
  kDexInvokeVirtual = 0,  // invoke-virtual, invoke-virtual-range
  kDexInvokeSuper,        // invoke-super, invoke-super-range
  kDexInvokeDirect,       // invoke-direct, invoke-direct-range
  kDexInvokeStatic,       // invoke-static, invoke-static-range
  kDexInvokeInterface,    // invoke-interface, invoke-interface-range
  kDexInvokeTypeCount
};

// Dex instruction memory access types correspond to the ordering of GET/PUT instructions;
// this order is the same for IGET, IPUT, SGET, SPUT, AGET and APUT.
enum DexMemAccessType : uint8_t {
  kDexMemAccessWord = 0,  // op         0; int or float, the actual type is not encoded.
  kDexMemAccessWide,      // op_WIDE    1; long or double, the actual type is not encoded.
  kDexMemAccessObject,    // op_OBJECT  2; the actual reference type is not encoded.
  kDexMemAccessBoolean,   // op_BOOLEAN 3
  kDexMemAccessByte,      // op_BYTE    4
  kDexMemAccessChar,      // op_CHAR    5
  kDexMemAccessShort,     // op_SHORT   6
  kDexMemAccessTypeCount
};

std::ostream& operator<<(std::ostream& os, const DexMemAccessType& type);

// NOTE: The following functions disregard quickened instructions.

constexpr bool IsInstructionReturn(Instruction::Code opcode) {
  return Instruction::RETURN_VOID <= opcode && opcode <= Instruction::RETURN_OBJECT;
}

constexpr bool IsInstructionInvoke(Instruction::Code opcode) {
  return Instruction::INVOKE_VIRTUAL <= opcode && opcode <= Instruction::INVOKE_INTERFACE_RANGE &&
      opcode != Instruction::RETURN_VOID_NO_BARRIER;
}

constexpr bool IsInstructionQuickInvoke(Instruction::Code opcode) {
  return opcode == Instruction::INVOKE_VIRTUAL_QUICK ||
      opcode == Instruction::INVOKE_VIRTUAL_RANGE_QUICK;
}

constexpr bool IsInstructionInvokeStatic(Instruction::Code opcode) {
  return opcode == Instruction::INVOKE_STATIC || opcode == Instruction::INVOKE_STATIC_RANGE;
}

constexpr bool IsInstructionGoto(Instruction::Code opcode) {
  return Instruction::GOTO <= opcode && opcode <= Instruction::GOTO_32;
}

constexpr bool IsInstructionIfCc(Instruction::Code opcode) {
  return Instruction::IF_EQ <= opcode && opcode <= Instruction::IF_LE;
}

constexpr bool IsInstructionIfCcZ(Instruction::Code opcode) {
  return Instruction::IF_EQZ <= opcode && opcode <= Instruction::IF_LEZ;
}

constexpr bool IsInstructionIGet(Instruction::Code code) {
  return Instruction::IGET <= code && code <= Instruction::IGET_SHORT;
}

constexpr bool IsInstructionIPut(Instruction::Code code) {
  return Instruction::IPUT <= code && code <= Instruction::IPUT_SHORT;
}

constexpr bool IsInstructionSGet(Instruction::Code code) {
  return Instruction::SGET <= code && code <= Instruction::SGET_SHORT;
}

constexpr bool IsInstructionSPut(Instruction::Code code) {
  return Instruction::SPUT <= code && code <= Instruction::SPUT_SHORT;
}

constexpr bool IsInstructionAGet(Instruction::Code code) {
  return Instruction::AGET <= code && code <= Instruction::AGET_SHORT;
}

constexpr bool IsInstructionAPut(Instruction::Code code) {
  return Instruction::APUT <= code && code <= Instruction::APUT_SHORT;
}

constexpr bool IsInstructionIGetOrIPut(Instruction::Code code) {
  return Instruction::IGET <= code && code <= Instruction::IPUT_SHORT;
}

constexpr bool IsInstructionIGetQuickOrIPutQuick(Instruction::Code code) {
  return (code >= Instruction::IGET_QUICK && code <= Instruction::IPUT_OBJECT_QUICK) ||
      (code >= Instruction::IPUT_BOOLEAN_QUICK && code <= Instruction::IGET_SHORT_QUICK);
}

constexpr bool IsInstructionSGetOrSPut(Instruction::Code code) {
  return Instruction::SGET <= code && code <= Instruction::SPUT_SHORT;
}

constexpr bool IsInstructionAGetOrAPut(Instruction::Code code) {
  return Instruction::AGET <= code && code <= Instruction::APUT_SHORT;
}

constexpr bool IsInstructionBinOp2Addr(Instruction::Code code) {
  return Instruction::ADD_INT_2ADDR <= code && code <= Instruction::REM_DOUBLE_2ADDR;
}

// TODO: Remove the #if guards below when we fully migrate to C++14.

constexpr bool IsInvokeInstructionRange(Instruction::Code opcode) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionInvoke(opcode));
#endif
  return opcode >= Instruction::INVOKE_VIRTUAL_RANGE;
}

constexpr DexInvokeType InvokeInstructionType(Instruction::Code opcode) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionInvoke(opcode));
#endif
  return static_cast<DexInvokeType>(IsInvokeInstructionRange(opcode)
                                    ? (opcode - Instruction::INVOKE_VIRTUAL_RANGE)
                                    : (opcode - Instruction::INVOKE_VIRTUAL));
}

constexpr DexMemAccessType IGetMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionIGet(opcode));
#endif
  return static_cast<DexMemAccessType>(code - Instruction::IGET);
}

constexpr DexMemAccessType IPutMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionIPut(opcode));
#endif
  return static_cast<DexMemAccessType>(code - Instruction::IPUT);
}

constexpr DexMemAccessType SGetMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionSGet(opcode));
#endif
  return static_cast<DexMemAccessType>(code - Instruction::SGET);
}

constexpr DexMemAccessType SPutMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionSPut(opcode));
#endif
  return static_cast<DexMemAccessType>(code - Instruction::SPUT);
}

constexpr DexMemAccessType AGetMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionAGet(opcode));
#endif
  return static_cast<DexMemAccessType>(code - Instruction::AGET);
}

constexpr DexMemAccessType APutMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionAPut(opcode));
#endif
  return static_cast<DexMemAccessType>(code - Instruction::APUT);
}

constexpr DexMemAccessType IGetOrIPutMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionIGetOrIPut(opcode));
#endif
  return (code >= Instruction::IPUT) ? IPutMemAccessType(code) : IGetMemAccessType(code);
}

static inline DexMemAccessType IGetQuickOrIPutQuickMemAccessType(Instruction::Code code) {
  DCHECK(IsInstructionIGetQuickOrIPutQuick(code));
  switch (code) {
    case Instruction::IGET_QUICK: case Instruction::IPUT_QUICK:
      return kDexMemAccessWord;
    case Instruction::IGET_WIDE_QUICK: case Instruction::IPUT_WIDE_QUICK:
      return kDexMemAccessWide;
    case Instruction::IGET_OBJECT_QUICK: case Instruction::IPUT_OBJECT_QUICK:
      return kDexMemAccessObject;
    case Instruction::IGET_BOOLEAN_QUICK: case Instruction::IPUT_BOOLEAN_QUICK:
      return kDexMemAccessBoolean;
    case Instruction::IGET_BYTE_QUICK: case Instruction::IPUT_BYTE_QUICK:
      return kDexMemAccessByte;
    case Instruction::IGET_CHAR_QUICK: case Instruction::IPUT_CHAR_QUICK:
      return kDexMemAccessChar;
    case Instruction::IGET_SHORT_QUICK: case Instruction::IPUT_SHORT_QUICK:
      return kDexMemAccessShort;
    default:
      LOG(FATAL) << code;
      UNREACHABLE();
  }
}

constexpr DexMemAccessType SGetOrSPutMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionSGetOrSPut(opcode));
#endif
  return (code >= Instruction::SPUT) ? SPutMemAccessType(code) : SGetMemAccessType(code);
}

constexpr DexMemAccessType AGetOrAPutMemAccessType(Instruction::Code code) {
#if __cplusplus >= 201402  // C++14 allows the DCHECK() in constexpr functions.
  DCHECK(IsInstructionAGetOrAPut(opcode));
#endif
  return (code >= Instruction::APUT) ? APutMemAccessType(code) : AGetMemAccessType(code);
}

}  // namespace art

#endif  // ART_RUNTIME_DEX_INSTRUCTION_UTILS_H_