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