1 /*
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 */
16
17 #ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
18 #define ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
19
20 #include <iosfwd>
21 #include <string>
22
23 #include "base/enums.h"
24 #include "base/macros.h"
25
26 namespace art {
27
28 enum class InstructionSet {
29 kNone,
30 kArm,
31 kArm64,
32 kThumb2,
33 kX86,
34 kX86_64,
35 kMips,
36 kMips64,
37 kLast = kMips64
38 };
39 std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
40
41 #if defined(__arm__)
42 static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm;
43 #elif defined(__aarch64__)
44 static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm64;
45 #elif defined(__mips__) && !defined(__LP64__)
46 static constexpr InstructionSet kRuntimeISA = InstructionSet::kMips;
47 #elif defined(__mips__) && defined(__LP64__)
48 static constexpr InstructionSet kRuntimeISA = InstructionSet::kMips64;
49 #elif defined(__i386__)
50 static constexpr InstructionSet kRuntimeISA = InstructionSet::kX86;
51 #elif defined(__x86_64__)
52 static constexpr InstructionSet kRuntimeISA = InstructionSet::kX86_64;
53 #else
54 static constexpr InstructionSet kRuntimeISA = InstructionSet::kNone;
55 #endif
56
57 // Architecture-specific pointer sizes
58 static constexpr PointerSize kArmPointerSize = PointerSize::k32;
59 static constexpr PointerSize kArm64PointerSize = PointerSize::k64;
60 static constexpr PointerSize kMipsPointerSize = PointerSize::k32;
61 static constexpr PointerSize kMips64PointerSize = PointerSize::k64;
62 static constexpr PointerSize kX86PointerSize = PointerSize::k32;
63 static constexpr PointerSize kX86_64PointerSize = PointerSize::k64;
64
65 // ARM instruction alignment. ARM processors require code to be 4-byte aligned,
66 // but ARM ELF requires 8..
67 static constexpr size_t kArmAlignment = 8;
68
69 // ARM64 instruction alignment. This is the recommended alignment for maximum performance.
70 static constexpr size_t kArm64Alignment = 16;
71
72 // MIPS instruction alignment. MIPS processors require code to be 4-byte aligned,
73 // but 64-bit literals must be 8-byte aligned.
74 static constexpr size_t kMipsAlignment = 8;
75
76 // X86 instruction alignment. This is the recommended alignment for maximum performance.
77 static constexpr size_t kX86Alignment = 16;
78
79 // Different than code alignment since code alignment is only first instruction of method.
80 static constexpr size_t kThumb2InstructionAlignment = 2;
81 static constexpr size_t kArm64InstructionAlignment = 4;
82 static constexpr size_t kX86InstructionAlignment = 1;
83 static constexpr size_t kX86_64InstructionAlignment = 1;
84 static constexpr size_t kMipsInstructionAlignment = 4;
85 static constexpr size_t kMips64InstructionAlignment = 4;
86
87 const char* GetInstructionSetString(InstructionSet isa);
88
89 // Note: Returns kNone when the string cannot be parsed to a known value.
90 InstructionSet GetInstructionSetFromString(const char* instruction_set);
91
92 InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags);
93
94 // Fatal logging out of line to keep the header clean of logging.h.
95 NO_RETURN void InstructionSetAbort(InstructionSet isa);
96
GetInstructionSetPointerSize(InstructionSet isa)97 constexpr PointerSize GetInstructionSetPointerSize(InstructionSet isa) {
98 switch (isa) {
99 case InstructionSet::kArm:
100 // Fall-through.
101 case InstructionSet::kThumb2:
102 return kArmPointerSize;
103 case InstructionSet::kArm64:
104 return kArm64PointerSize;
105 case InstructionSet::kX86:
106 return kX86PointerSize;
107 case InstructionSet::kX86_64:
108 return kX86_64PointerSize;
109 case InstructionSet::kMips:
110 return kMipsPointerSize;
111 case InstructionSet::kMips64:
112 return kMips64PointerSize;
113
114 case InstructionSet::kNone:
115 break;
116 }
117 InstructionSetAbort(isa);
118 }
119
GetInstructionSetInstructionAlignment(InstructionSet isa)120 constexpr size_t GetInstructionSetInstructionAlignment(InstructionSet isa) {
121 switch (isa) {
122 case InstructionSet::kArm:
123 // Fall-through.
124 case InstructionSet::kThumb2:
125 return kThumb2InstructionAlignment;
126 case InstructionSet::kArm64:
127 return kArm64InstructionAlignment;
128 case InstructionSet::kX86:
129 return kX86InstructionAlignment;
130 case InstructionSet::kX86_64:
131 return kX86_64InstructionAlignment;
132 case InstructionSet::kMips:
133 return kMipsInstructionAlignment;
134 case InstructionSet::kMips64:
135 return kMips64InstructionAlignment;
136
137 case InstructionSet::kNone:
138 break;
139 }
140 InstructionSetAbort(isa);
141 }
142
IsValidInstructionSet(InstructionSet isa)143 constexpr bool IsValidInstructionSet(InstructionSet isa) {
144 switch (isa) {
145 case InstructionSet::kArm:
146 case InstructionSet::kThumb2:
147 case InstructionSet::kArm64:
148 case InstructionSet::kX86:
149 case InstructionSet::kX86_64:
150 case InstructionSet::kMips:
151 case InstructionSet::kMips64:
152 return true;
153
154 case InstructionSet::kNone:
155 return false;
156 }
157 return false;
158 }
159
160 size_t GetInstructionSetAlignment(InstructionSet isa);
161
Is64BitInstructionSet(InstructionSet isa)162 constexpr bool Is64BitInstructionSet(InstructionSet isa) {
163 switch (isa) {
164 case InstructionSet::kArm:
165 case InstructionSet::kThumb2:
166 case InstructionSet::kX86:
167 case InstructionSet::kMips:
168 return false;
169
170 case InstructionSet::kArm64:
171 case InstructionSet::kX86_64:
172 case InstructionSet::kMips64:
173 return true;
174
175 case InstructionSet::kNone:
176 break;
177 }
178 InstructionSetAbort(isa);
179 }
180
InstructionSetPointerSize(InstructionSet isa)181 constexpr PointerSize InstructionSetPointerSize(InstructionSet isa) {
182 return Is64BitInstructionSet(isa) ? PointerSize::k64 : PointerSize::k32;
183 }
184
GetBytesPerGprSpillLocation(InstructionSet isa)185 constexpr size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
186 switch (isa) {
187 case InstructionSet::kArm:
188 // Fall-through.
189 case InstructionSet::kThumb2:
190 return 4;
191 case InstructionSet::kArm64:
192 return 8;
193 case InstructionSet::kX86:
194 return 4;
195 case InstructionSet::kX86_64:
196 return 8;
197 case InstructionSet::kMips:
198 return 4;
199 case InstructionSet::kMips64:
200 return 8;
201
202 case InstructionSet::kNone:
203 break;
204 }
205 InstructionSetAbort(isa);
206 }
207
GetBytesPerFprSpillLocation(InstructionSet isa)208 constexpr size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
209 switch (isa) {
210 case InstructionSet::kArm:
211 // Fall-through.
212 case InstructionSet::kThumb2:
213 return 4;
214 case InstructionSet::kArm64:
215 return 8;
216 case InstructionSet::kX86:
217 return 8;
218 case InstructionSet::kX86_64:
219 return 8;
220 case InstructionSet::kMips:
221 return 4;
222 case InstructionSet::kMips64:
223 return 8;
224
225 case InstructionSet::kNone:
226 break;
227 }
228 InstructionSetAbort(isa);
229 }
230
231 size_t GetStackOverflowReservedBytes(InstructionSet isa);
232
233 // The following definitions create return types for two word-sized entities that will be passed
234 // in registers so that memory operations for the interface trampolines can be avoided. The entities
235 // are the resolved method and the pointer to the code to be invoked.
236 //
237 // On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
238 // uint64_t or long long int.
239 //
240 // On x86_64, ARM64 and MIPS64, structs are decomposed for allocation, so we can create a structs of
241 // two size_t-sized values.
242 //
243 // We need two operations:
244 //
245 // 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
246 // GetTwoWordFailureValue() will return a value that has lower part == 0.
247 //
248 // 2) A value that combines two word-sized values.
249 // GetTwoWordSuccessValue() constructs this.
250 //
251 // IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
252 // that the object does not move or the value is updated. Simple use of this is NOT SAFE
253 // when the garbage collector can move objects concurrently. Ensure that required locks
254 // are held when using!
255
256 #if defined(__i386__) || defined(__arm__) || (defined(__mips__) && !defined(__LP64__))
257 typedef uint64_t TwoWordReturn;
258
259 // Encodes method_ptr==nullptr and code_ptr==nullptr
GetTwoWordFailureValue()260 static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
261 return 0;
262 }
263
264 // Use the lower 32b for the method pointer and the upper 32b for the code pointer.
GetTwoWordSuccessValue(uintptr_t hi,uintptr_t lo)265 static inline constexpr TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
266 static_assert(sizeof(uint32_t) == sizeof(uintptr_t), "Unexpected size difference");
267 uint32_t lo32 = lo;
268 uint64_t hi64 = static_cast<uint64_t>(hi);
269 return ((hi64 << 32) | lo32);
270 }
271
272 #elif defined(__x86_64__) || defined(__aarch64__) || (defined(__mips__) && defined(__LP64__))
273
274 // Note: TwoWordReturn can't be constexpr for 64-bit targets. We'd need a constexpr constructor,
275 // which would violate C-linkage in the entrypoint functions.
276
277 struct TwoWordReturn {
278 uintptr_t lo;
279 uintptr_t hi;
280 };
281
282 // Encodes method_ptr==nullptr. Leaves random value in code pointer.
GetTwoWordFailureValue()283 static inline TwoWordReturn GetTwoWordFailureValue() {
284 TwoWordReturn ret;
285 ret.lo = 0;
286 return ret;
287 }
288
289 // Write values into their respective members.
GetTwoWordSuccessValue(uintptr_t hi,uintptr_t lo)290 static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
291 TwoWordReturn ret;
292 ret.lo = lo;
293 ret.hi = hi;
294 return ret;
295 }
296 #else
297 #error "Unsupported architecture"
298 #endif
299
300 } // namespace art
301
302 #endif // ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
303