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