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