diff options
Diffstat (limited to 'runtime/instruction_set.h')
| -rw-r--r-- | runtime/instruction_set.h | 179 |
1 files changed, 175 insertions, 4 deletions
diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h index 679c575a47..67e7100873 100644 --- a/runtime/instruction_set.h +++ b/runtime/instruction_set.h @@ -20,6 +20,7 @@ #include <iosfwd> #include <string> +#include "base/logging.h" // Logging is required for FATAL in the helper functions. #include "base/macros.h" namespace art { @@ -35,14 +36,122 @@ enum InstructionSet { }; std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs); +// Architecture-specific pointer sizes +static constexpr size_t kArmPointerSize = 4; +static constexpr size_t kArm64PointerSize = 8; +static constexpr size_t kMipsPointerSize = 4; +static constexpr size_t kX86PointerSize = 4; +static constexpr size_t kX86_64PointerSize = 8; + +// ARM instruction alignment. ARM processors require code to be 4-byte aligned, +// but ARM ELF requires 8.. +static constexpr size_t kArmAlignment = 8; + +// ARM64 instruction alignment. This is the recommended alignment for maximum performance. +static constexpr size_t kArm64Alignment = 16; + +// MIPS instruction alignment. MIPS processors require code to be 4-byte aligned. +// TODO: Can this be 4? +static constexpr size_t kMipsAlignment = 8; + +// X86 instruction alignment. This is the recommended alignment for maximum performance. +static constexpr size_t kX86Alignment = 16; + + const char* GetInstructionSetString(InstructionSet isa); InstructionSet GetInstructionSetFromString(const char* instruction_set); -size_t GetInstructionSetPointerSize(InstructionSet isa); +static inline size_t GetInstructionSetPointerSize(InstructionSet isa) { + switch (isa) { + case kArm: + // Fall-through. + case kThumb2: + return kArmPointerSize; + case kArm64: + return kArm64PointerSize; + case kX86: + return kX86PointerSize; + case kX86_64: + return kX86_64PointerSize; + case kMips: + return kMipsPointerSize; + case kNone: + LOG(FATAL) << "ISA kNone does not have pointer size."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} + size_t GetInstructionSetAlignment(InstructionSet isa); -bool Is64BitInstructionSet(InstructionSet isa); -size_t GetBytesPerGprSpillLocation(InstructionSet isa); -size_t GetBytesPerFprSpillLocation(InstructionSet isa); + +static inline bool Is64BitInstructionSet(InstructionSet isa) { + switch (isa) { + case kArm: + case kThumb2: + case kX86: + case kMips: + return false; + + case kArm64: + case kX86_64: + return true; + + case kNone: + LOG(FATAL) << "ISA kNone does not have bit width."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} + +static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) { + switch (isa) { + case kArm: + // Fall-through. + case kThumb2: + return 4; + case kArm64: + return 8; + case kX86: + return 4; + case kX86_64: + return 8; + case kMips: + return 4; + case kNone: + LOG(FATAL) << "ISA kNone does not have spills."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} + +static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) { + switch (isa) { + case kArm: + // Fall-through. + case kThumb2: + return 4; + case kArm64: + return 8; + case kX86: + return 8; + case kX86_64: + return 8; + case kMips: + return 4; + case kNone: + LOG(FATAL) << "ISA kNone does not have spills."; + return 0; + default: + LOG(FATAL) << "Unknown ISA " << isa; + return 0; + } +} #if defined(__arm__) static constexpr InstructionSet kRuntimeISA = kArm; @@ -107,6 +216,68 @@ class PACKED(4) InstructionSetFeatures { uint32_t mask_; }; +// The following definitions create return types for two word-sized entities that will be passed +// in registers so that memory operations for the interface trampolines can be avoided. The entities +// are the resolved method and the pointer to the code to be invoked. +// +// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be +// uint64_t or long long int. +// +// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two +// size_t-sized values. +// +// We need two operations: +// +// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0". +// GetTwoWordFailureValue() will return a value that has lower part == 0. +// +// 2) A value that combines two word-sized values. +// GetTwoWordSuccessValue() constructs this. +// +// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure +// that the object does not move or the value is updated. Simple use of this is NOT SAFE +// when the garbage collector can move objects concurrently. Ensure that required locks +// are held when using! + +#if defined(__i386__) || defined(__arm__) || defined(__mips__) +typedef uint64_t TwoWordReturn; + +// Encodes method_ptr==nullptr and code_ptr==nullptr +static inline constexpr TwoWordReturn GetTwoWordFailureValue() { + return 0; +} + +// Use the lower 32b for the method pointer and the upper 32b for the code pointer. +static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) { + uint32_t lo32 = static_cast<uint32_t>(lo); + uint64_t hi64 = static_cast<uint64_t>(hi); + return ((hi64 << 32) | lo32); +} + +#elif defined(__x86_64__) || defined(__aarch64__) +struct TwoWordReturn { + uintptr_t lo; + uintptr_t hi; +}; + +// Encodes method_ptr==nullptr. Leaves random value in code pointer. +static inline TwoWordReturn GetTwoWordFailureValue() { + TwoWordReturn ret; + ret.lo = 0; + return ret; +} + +// Write values into their respective members. +static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) { + TwoWordReturn ret; + ret.lo = lo; + ret.hi = hi; + return ret; +} +#else +#error "Unsupported architecture" +#endif + } // namespace art #endif // ART_RUNTIME_INSTRUCTION_SET_H_ |