blob: 7e071bd9e223fed96cc4f7582b659be4840de8cc [file] [log] [blame]
Ian Rogersd582fa42014-11-05 23:46:43 -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 */
16
David Sehrc3e18952018-05-11 16:59:31 -070017#ifndef ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_
18#define ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_
Ian Rogersd582fa42014-11-05 23:46:43 -080019
20#include <iosfwd>
21#include <string>
22
Andreas Gampe542451c2016-07-26 09:02:02 -070023#include "base/enums.h"
Andreas Gampebda1d602016-08-29 17:43:45 -070024#include "base/macros.h"
Ian Rogersd582fa42014-11-05 23:46:43 -080025
26namespace art {
27
Vladimir Marko33bff252017-11-01 14:35:42 +000028enum class InstructionSet {
Ian Rogersd582fa42014-11-05 23:46:43 -080029 kNone,
30 kArm,
31 kArm64,
32 kThumb2,
33 kX86,
34 kX86_64,
35 kMips,
Vladimir Marko33bff252017-11-01 14:35:42 +000036 kMips64,
37 kLast = kMips64
Ian Rogersd582fa42014-11-05 23:46:43 -080038};
39std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
40
41#if defined(__arm__)
Vladimir Marko33bff252017-11-01 14:35:42 +000042static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm;
Ian Rogersd582fa42014-11-05 23:46:43 -080043#elif defined(__aarch64__)
Vladimir Marko33bff252017-11-01 14:35:42 +000044static constexpr InstructionSet kRuntimeISA = InstructionSet::kArm64;
Andreas Gampe57b34292015-01-14 15:45:59 -080045#elif defined(__mips__) && !defined(__LP64__)
Vladimir Marko33bff252017-11-01 14:35:42 +000046static constexpr InstructionSet kRuntimeISA = InstructionSet::kMips;
Andreas Gampe57b34292015-01-14 15:45:59 -080047#elif defined(__mips__) && defined(__LP64__)
Vladimir Marko33bff252017-11-01 14:35:42 +000048static constexpr InstructionSet kRuntimeISA = InstructionSet::kMips64;
Ian Rogersd582fa42014-11-05 23:46:43 -080049#elif defined(__i386__)
Vladimir Marko33bff252017-11-01 14:35:42 +000050static constexpr InstructionSet kRuntimeISA = InstructionSet::kX86;
Ian Rogersd582fa42014-11-05 23:46:43 -080051#elif defined(__x86_64__)
Vladimir Marko33bff252017-11-01 14:35:42 +000052static constexpr InstructionSet kRuntimeISA = InstructionSet::kX86_64;
Ian Rogersd582fa42014-11-05 23:46:43 -080053#else
Vladimir Marko33bff252017-11-01 14:35:42 +000054static constexpr InstructionSet kRuntimeISA = InstructionSet::kNone;
Ian Rogersd582fa42014-11-05 23:46:43 -080055#endif
56
57// Architecture-specific pointer sizes
Andreas Gampe542451c2016-07-26 09:02:02 -070058static constexpr PointerSize kArmPointerSize = PointerSize::k32;
59static constexpr PointerSize kArm64PointerSize = PointerSize::k64;
60static constexpr PointerSize kMipsPointerSize = PointerSize::k32;
61static constexpr PointerSize kMips64PointerSize = PointerSize::k64;
62static constexpr PointerSize kX86PointerSize = PointerSize::k32;
63static constexpr PointerSize kX86_64PointerSize = PointerSize::k64;
Ian Rogersd582fa42014-11-05 23:46:43 -080064
65// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
66// but ARM ELF requires 8..
67static constexpr size_t kArmAlignment = 8;
68
69// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
70static constexpr size_t kArm64Alignment = 16;
71
Alexey Frunze85885fe2017-02-01 16:25:37 -080072// MIPS instruction alignment. MIPS processors require code to be 4-byte aligned,
73// but 64-bit literals must be 8-byte aligned.
Ian Rogersd582fa42014-11-05 23:46:43 -080074static constexpr size_t kMipsAlignment = 8;
75
76// X86 instruction alignment. This is the recommended alignment for maximum performance.
77static constexpr size_t kX86Alignment = 16;
78
Mathieu Chartiera2f526f2017-01-19 14:48:48 -080079// Different than code alignment since code alignment is only first instruction of method.
80static constexpr size_t kThumb2InstructionAlignment = 2;
81static constexpr size_t kArm64InstructionAlignment = 4;
82static constexpr size_t kX86InstructionAlignment = 1;
83static constexpr size_t kX86_64InstructionAlignment = 1;
Alexey Frunze85885fe2017-02-01 16:25:37 -080084static constexpr size_t kMipsInstructionAlignment = 4;
85static constexpr size_t kMips64InstructionAlignment = 4;
Mathieu Chartiera2f526f2017-01-19 14:48:48 -080086
Ian Rogersd582fa42014-11-05 23:46:43 -080087const char* GetInstructionSetString(InstructionSet isa);
88
89// Note: Returns kNone when the string cannot be parsed to a known value.
90InstructionSet GetInstructionSetFromString(const char* instruction_set);
91
Andreas Gampebda1d602016-08-29 17:43:45 -070092// Fatal logging out of line to keep the header clean of logging.h.
93NO_RETURN void InstructionSetAbort(InstructionSet isa);
94
Andreas Gampe705543e2017-05-24 13:20:49 -070095constexpr PointerSize GetInstructionSetPointerSize(InstructionSet isa) {
Ian Rogersd582fa42014-11-05 23:46:43 -080096 switch (isa) {
Vladimir Marko33bff252017-11-01 14:35:42 +000097 case InstructionSet::kArm:
Ian Rogersd582fa42014-11-05 23:46:43 -080098 // Fall-through.
Vladimir Marko33bff252017-11-01 14:35:42 +000099 case InstructionSet::kThumb2:
Ian Rogersd582fa42014-11-05 23:46:43 -0800100 return kArmPointerSize;
Vladimir Marko33bff252017-11-01 14:35:42 +0000101 case InstructionSet::kArm64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800102 return kArm64PointerSize;
Vladimir Marko33bff252017-11-01 14:35:42 +0000103 case InstructionSet::kX86:
Ian Rogersd582fa42014-11-05 23:46:43 -0800104 return kX86PointerSize;
Vladimir Marko33bff252017-11-01 14:35:42 +0000105 case InstructionSet::kX86_64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800106 return kX86_64PointerSize;
Vladimir Marko33bff252017-11-01 14:35:42 +0000107 case InstructionSet::kMips:
Ian Rogersd582fa42014-11-05 23:46:43 -0800108 return kMipsPointerSize;
Vladimir Marko33bff252017-11-01 14:35:42 +0000109 case InstructionSet::kMips64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800110 return kMips64PointerSize;
Andreas Gampe705543e2017-05-24 13:20:49 -0700111
Vladimir Marko33bff252017-11-01 14:35:42 +0000112 case InstructionSet::kNone:
Andreas Gampe705543e2017-05-24 13:20:49 -0700113 break;
Ian Rogersd582fa42014-11-05 23:46:43 -0800114 }
Andreas Gampe705543e2017-05-24 13:20:49 -0700115 InstructionSetAbort(isa);
Ian Rogersd582fa42014-11-05 23:46:43 -0800116}
117
Andreas Gampe705543e2017-05-24 13:20:49 -0700118constexpr size_t GetInstructionSetInstructionAlignment(InstructionSet isa) {
119 switch (isa) {
Vladimir Marko33bff252017-11-01 14:35:42 +0000120 case InstructionSet::kArm:
Andreas Gampe705543e2017-05-24 13:20:49 -0700121 // Fall-through.
Vladimir Marko33bff252017-11-01 14:35:42 +0000122 case InstructionSet::kThumb2:
Andreas Gampe705543e2017-05-24 13:20:49 -0700123 return kThumb2InstructionAlignment;
Vladimir Marko33bff252017-11-01 14:35:42 +0000124 case InstructionSet::kArm64:
Andreas Gampe705543e2017-05-24 13:20:49 -0700125 return kArm64InstructionAlignment;
Vladimir Marko33bff252017-11-01 14:35:42 +0000126 case InstructionSet::kX86:
Andreas Gampe705543e2017-05-24 13:20:49 -0700127 return kX86InstructionAlignment;
Vladimir Marko33bff252017-11-01 14:35:42 +0000128 case InstructionSet::kX86_64:
Andreas Gampe705543e2017-05-24 13:20:49 -0700129 return kX86_64InstructionAlignment;
Vladimir Marko33bff252017-11-01 14:35:42 +0000130 case InstructionSet::kMips:
Andreas Gampe705543e2017-05-24 13:20:49 -0700131 return kMipsInstructionAlignment;
Vladimir Marko33bff252017-11-01 14:35:42 +0000132 case InstructionSet::kMips64:
Andreas Gampe705543e2017-05-24 13:20:49 -0700133 return kMips64InstructionAlignment;
134
Vladimir Marko33bff252017-11-01 14:35:42 +0000135 case InstructionSet::kNone:
Andreas Gampe705543e2017-05-24 13:20:49 -0700136 break;
137 }
138 InstructionSetAbort(isa);
Mathieu Chartiera2f526f2017-01-19 14:48:48 -0800139}
140
Andreas Gampe705543e2017-05-24 13:20:49 -0700141constexpr bool IsValidInstructionSet(InstructionSet isa) {
Vladimir Marko09d09432015-09-08 13:47:48 +0100142 switch (isa) {
Vladimir Marko33bff252017-11-01 14:35:42 +0000143 case InstructionSet::kArm:
144 case InstructionSet::kThumb2:
145 case InstructionSet::kArm64:
146 case InstructionSet::kX86:
147 case InstructionSet::kX86_64:
148 case InstructionSet::kMips:
149 case InstructionSet::kMips64:
Vladimir Marko09d09432015-09-08 13:47:48 +0100150 return true;
Andreas Gampe705543e2017-05-24 13:20:49 -0700151
Vladimir Marko33bff252017-11-01 14:35:42 +0000152 case InstructionSet::kNone:
Vladimir Marko09d09432015-09-08 13:47:48 +0100153 return false;
154 }
Andreas Gampe705543e2017-05-24 13:20:49 -0700155 return false;
Vladimir Marko09d09432015-09-08 13:47:48 +0100156}
157
Ian Rogersd582fa42014-11-05 23:46:43 -0800158size_t GetInstructionSetAlignment(InstructionSet isa);
159
Andreas Gampe705543e2017-05-24 13:20:49 -0700160constexpr bool Is64BitInstructionSet(InstructionSet isa) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800161 switch (isa) {
Vladimir Marko33bff252017-11-01 14:35:42 +0000162 case InstructionSet::kArm:
163 case InstructionSet::kThumb2:
164 case InstructionSet::kX86:
165 case InstructionSet::kMips:
Ian Rogersd582fa42014-11-05 23:46:43 -0800166 return false;
167
Vladimir Marko33bff252017-11-01 14:35:42 +0000168 case InstructionSet::kArm64:
169 case InstructionSet::kX86_64:
170 case InstructionSet::kMips64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800171 return true;
172
Vladimir Marko33bff252017-11-01 14:35:42 +0000173 case InstructionSet::kNone:
Andreas Gampe705543e2017-05-24 13:20:49 -0700174 break;
Ian Rogersd582fa42014-11-05 23:46:43 -0800175 }
Andreas Gampe705543e2017-05-24 13:20:49 -0700176 InstructionSetAbort(isa);
Ian Rogersd582fa42014-11-05 23:46:43 -0800177}
178
Andreas Gampe705543e2017-05-24 13:20:49 -0700179constexpr PointerSize InstructionSetPointerSize(InstructionSet isa) {
Andreas Gampe542451c2016-07-26 09:02:02 -0700180 return Is64BitInstructionSet(isa) ? PointerSize::k64 : PointerSize::k32;
Mathieu Chartier2d721012014-11-10 11:08:06 -0800181}
182
Andreas Gampe705543e2017-05-24 13:20:49 -0700183constexpr size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800184 switch (isa) {
Vladimir Marko33bff252017-11-01 14:35:42 +0000185 case InstructionSet::kArm:
Ian Rogersd582fa42014-11-05 23:46:43 -0800186 // Fall-through.
Vladimir Marko33bff252017-11-01 14:35:42 +0000187 case InstructionSet::kThumb2:
Ian Rogersd582fa42014-11-05 23:46:43 -0800188 return 4;
Vladimir Marko33bff252017-11-01 14:35:42 +0000189 case InstructionSet::kArm64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800190 return 8;
Vladimir Marko33bff252017-11-01 14:35:42 +0000191 case InstructionSet::kX86:
Ian Rogersd582fa42014-11-05 23:46:43 -0800192 return 4;
Vladimir Marko33bff252017-11-01 14:35:42 +0000193 case InstructionSet::kX86_64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800194 return 8;
Vladimir Marko33bff252017-11-01 14:35:42 +0000195 case InstructionSet::kMips:
Ian Rogersd582fa42014-11-05 23:46:43 -0800196 return 4;
Vladimir Marko33bff252017-11-01 14:35:42 +0000197 case InstructionSet::kMips64:
Andreas Gampe57b34292015-01-14 15:45:59 -0800198 return 8;
Andreas Gampebda1d602016-08-29 17:43:45 -0700199
Vladimir Marko33bff252017-11-01 14:35:42 +0000200 case InstructionSet::kNone:
Andreas Gampe705543e2017-05-24 13:20:49 -0700201 break;
Ian Rogersd582fa42014-11-05 23:46:43 -0800202 }
Andreas Gampe705543e2017-05-24 13:20:49 -0700203 InstructionSetAbort(isa);
Ian Rogersd582fa42014-11-05 23:46:43 -0800204}
205
Andreas Gampe705543e2017-05-24 13:20:49 -0700206constexpr size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800207 switch (isa) {
Vladimir Marko33bff252017-11-01 14:35:42 +0000208 case InstructionSet::kArm:
Ian Rogersd582fa42014-11-05 23:46:43 -0800209 // Fall-through.
Vladimir Marko33bff252017-11-01 14:35:42 +0000210 case InstructionSet::kThumb2:
Ian Rogersd582fa42014-11-05 23:46:43 -0800211 return 4;
Vladimir Marko33bff252017-11-01 14:35:42 +0000212 case InstructionSet::kArm64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800213 return 8;
Vladimir Marko33bff252017-11-01 14:35:42 +0000214 case InstructionSet::kX86:
Ian Rogersd582fa42014-11-05 23:46:43 -0800215 return 8;
Vladimir Marko33bff252017-11-01 14:35:42 +0000216 case InstructionSet::kX86_64:
Ian Rogersd582fa42014-11-05 23:46:43 -0800217 return 8;
Vladimir Marko33bff252017-11-01 14:35:42 +0000218 case InstructionSet::kMips:
Ian Rogersd582fa42014-11-05 23:46:43 -0800219 return 4;
Vladimir Marko33bff252017-11-01 14:35:42 +0000220 case InstructionSet::kMips64:
Andreas Gampe57b34292015-01-14 15:45:59 -0800221 return 8;
Andreas Gampebda1d602016-08-29 17:43:45 -0700222
Vladimir Marko33bff252017-11-01 14:35:42 +0000223 case InstructionSet::kNone:
Andreas Gampe705543e2017-05-24 13:20:49 -0700224 break;
Ian Rogersd582fa42014-11-05 23:46:43 -0800225 }
Andreas Gampe705543e2017-05-24 13:20:49 -0700226 InstructionSetAbort(isa);
Ian Rogersd582fa42014-11-05 23:46:43 -0800227}
228
Andreas Gampea9b2f7b2018-11-01 11:10:03 -0700229namespace instruction_set_details {
230
231#if !defined(ART_STACK_OVERFLOW_GAP_arm) || !defined(ART_STACK_OVERFLOW_GAP_arm64) || \
232 !defined(ART_STACK_OVERFLOW_GAP_mips) || !defined(ART_STACK_OVERFLOW_GAP_mips64) || \
233 !defined(ART_STACK_OVERFLOW_GAP_x86) || !defined(ART_STACK_OVERFLOW_GAP_x86_64)
234#error "Missing defines for stack overflow gap"
235#endif
236
237static constexpr size_t kArmStackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_arm;
238static constexpr size_t kArm64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_arm64;
239static constexpr size_t kMipsStackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_mips;
240static constexpr size_t kMips64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_mips64;
241static constexpr size_t kX86StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_x86;
242static constexpr size_t kX86_64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_x86_64;
243
244NO_RETURN void GetStackOverflowReservedBytesFailure(const char* error_msg);
245
246} // namespace instruction_set_details
247
248ALWAYS_INLINE
249constexpr size_t GetStackOverflowReservedBytes(InstructionSet isa) {
250 switch (isa) {
251 case InstructionSet::kArm: // Intentional fall-through.
252 case InstructionSet::kThumb2:
253 return instruction_set_details::kArmStackOverflowReservedBytes;
254
255 case InstructionSet::kArm64:
256 return instruction_set_details::kArm64StackOverflowReservedBytes;
257
258 case InstructionSet::kMips:
259 return instruction_set_details::kMipsStackOverflowReservedBytes;
260
261 case InstructionSet::kMips64:
262 return instruction_set_details::kMips64StackOverflowReservedBytes;
263
264 case InstructionSet::kX86:
265 return instruction_set_details::kX86StackOverflowReservedBytes;
266
267 case InstructionSet::kX86_64:
268 return instruction_set_details::kX86_64StackOverflowReservedBytes;
269
270 case InstructionSet::kNone:
271 instruction_set_details::GetStackOverflowReservedBytesFailure(
272 "kNone has no stack overflow size");
273 }
274 instruction_set_details::GetStackOverflowReservedBytesFailure("Unknown instruction set");
275}
Ian Rogersd582fa42014-11-05 23:46:43 -0800276
277// The following definitions create return types for two word-sized entities that will be passed
278// in registers so that memory operations for the interface trampolines can be avoided. The entities
279// are the resolved method and the pointer to the code to be invoked.
280//
281// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
282// uint64_t or long long int.
283//
Andreas Gampe57b34292015-01-14 15:45:59 -0800284// On x86_64, ARM64 and MIPS64, structs are decomposed for allocation, so we can create a structs of
285// two size_t-sized values.
Ian Rogersd582fa42014-11-05 23:46:43 -0800286//
287// We need two operations:
288//
289// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
290// GetTwoWordFailureValue() will return a value that has lower part == 0.
291//
292// 2) A value that combines two word-sized values.
293// GetTwoWordSuccessValue() constructs this.
294//
295// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
296// that the object does not move or the value is updated. Simple use of this is NOT SAFE
297// when the garbage collector can move objects concurrently. Ensure that required locks
298// are held when using!
299
Andreas Gampe57b34292015-01-14 15:45:59 -0800300#if defined(__i386__) || defined(__arm__) || (defined(__mips__) && !defined(__LP64__))
Ian Rogersd582fa42014-11-05 23:46:43 -0800301typedef uint64_t TwoWordReturn;
302
303// Encodes method_ptr==nullptr and code_ptr==nullptr
304static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
305 return 0;
306}
307
308// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
Andreas Gampe705543e2017-05-24 13:20:49 -0700309static inline constexpr TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800310 static_assert(sizeof(uint32_t) == sizeof(uintptr_t), "Unexpected size difference");
311 uint32_t lo32 = lo;
312 uint64_t hi64 = static_cast<uint64_t>(hi);
313 return ((hi64 << 32) | lo32);
314}
315
Andreas Gampe57b34292015-01-14 15:45:59 -0800316#elif defined(__x86_64__) || defined(__aarch64__) || (defined(__mips__) && defined(__LP64__))
Andreas Gampe705543e2017-05-24 13:20:49 -0700317
318// Note: TwoWordReturn can't be constexpr for 64-bit targets. We'd need a constexpr constructor,
319// which would violate C-linkage in the entrypoint functions.
320
Ian Rogersd582fa42014-11-05 23:46:43 -0800321struct TwoWordReturn {
322 uintptr_t lo;
323 uintptr_t hi;
324};
325
326// Encodes method_ptr==nullptr. Leaves random value in code pointer.
327static inline TwoWordReturn GetTwoWordFailureValue() {
328 TwoWordReturn ret;
329 ret.lo = 0;
330 return ret;
331}
332
333// Write values into their respective members.
334static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
335 TwoWordReturn ret;
336 ret.lo = lo;
337 ret.hi = hi;
338 return ret;
339}
340#else
341#error "Unsupported architecture"
342#endif
343
344} // namespace art
345
David Sehrc3e18952018-05-11 16:59:31 -0700346#endif // ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_