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