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