1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_CONSTANTS_X64_H_
6#define RUNTIME_VM_CONSTANTS_X64_H_
7
8#ifndef RUNTIME_VM_CONSTANTS_H_
9#error Do not include constants_x64.h directly; use constants.h instead.
10#endif
11
12#include "platform/assert.h"
13#include "platform/globals.h"
14
15#include "vm/constants_base.h"
16
17namespace dart {
18
19enum Register {
20 RAX = 0,
21 RCX = 1,
22 RDX = 2,
23 RBX = 3,
24 RSP = 4,
25 RBP = 5,
26 RSI = 6,
27 RDI = 7,
28 R8 = 8,
29 R9 = 9,
30 R10 = 10,
31 R11 = 11,
32 R12 = 12,
33 R13 = 13,
34 R14 = 14,
35 R15 = 15,
36 kNumberOfCpuRegisters = 16,
37 kNoRegister = -1, // Signals an illegal register.
38};
39
40enum ByteRegister {
41 AL = 0,
42 CL = 1,
43 DL = 2,
44 BL = 3,
45 AH = 4,
46 CH = 5,
47 DH = 6,
48 BH = 7,
49 SPL = 4 | 0x10,
50 BPL = 5 | 0x10,
51 SIL = 6 | 0x10,
52 DIL = 7 | 0x10,
53 R8B = 8,
54 R9B = 9,
55 R10B = 10,
56 R11B = 11,
57 R12B = 12,
58 R13B = 13,
59 R14B = 14,
60 R15B = 15,
61 kNoByteRegister = -1 // Signals an illegal register.
62};
63
64inline ByteRegister ByteRegisterOf(Register reg) {
65 if (RSP <= reg && reg <= RDI) {
66 return static_cast<ByteRegister>(reg | 0x10);
67 } else {
68 return static_cast<ByteRegister>(reg);
69 }
70}
71
72enum XmmRegister {
73 XMM0 = 0,
74 XMM1 = 1,
75 XMM2 = 2,
76 XMM3 = 3,
77 XMM4 = 4,
78 XMM5 = 5,
79 XMM6 = 6,
80 XMM7 = 7,
81 XMM8 = 8,
82 XMM9 = 9,
83 XMM10 = 10,
84 XMM11 = 11,
85 XMM12 = 12,
86 XMM13 = 13,
87 XMM14 = 14,
88 XMM15 = 15,
89 kNumberOfXmmRegisters = 16,
90 kNoXmmRegister = -1 // Signals an illegal register.
91};
92
93// Architecture independent aliases.
94typedef XmmRegister FpuRegister;
95const FpuRegister FpuTMP = XMM15;
96const int kNumberOfFpuRegisters = kNumberOfXmmRegisters;
97const FpuRegister kNoFpuRegister = kNoXmmRegister;
98
99extern const char* cpu_reg_names[kNumberOfCpuRegisters];
100extern const char* fpu_reg_names[kNumberOfXmmRegisters];
101
102enum RexBits {
103 REX_NONE = 0,
104 REX_B = 1 << 0,
105 REX_X = 1 << 1,
106 REX_R = 1 << 2,
107 REX_W = 1 << 3,
108 REX_PREFIX = 1 << 6
109};
110
111// Register aliases.
112const Register TMP = R11; // Used as scratch register by the assembler.
113const Register TMP2 = kNoRegister; // No second assembler scratch register.
114// Caches object pool pointer in generated code.
115const Register PP = R15;
116const Register SPREG = RSP; // Stack pointer register.
117const Register FPREG = RBP; // Frame pointer register.
118const Register ARGS_DESC_REG = R10; // Arguments descriptor register.
119const Register CODE_REG = R12;
120const Register THR = R14; // Caches current thread in generated code.
121const Register CALLEE_SAVED_TEMP = RBX;
122
123// ABI for catch-clause entry point.
124const Register kExceptionObjectReg = RAX;
125const Register kStackTraceObjectReg = RDX;
126
127// ABI for write barrier stub.
128const Register kWriteBarrierObjectReg = RDX;
129const Register kWriteBarrierValueReg = RAX;
130const Register kWriteBarrierSlotReg = R13;
131
132// ABI for allocation stubs.
133const Register kAllocationStubTypeArgumentsReg = RDX;
134
135// ABI for instantiation stubs.
136struct InstantiationABI {
137 static const Register kUninstantiatedTypeArgumentsReg = RBX;
138 static const Register kInstantiatorTypeArgumentsReg = RDX;
139 static const Register kFunctionTypeArgumentsReg = RCX;
140 static const Register kResultTypeArgumentsReg = RAX;
141 static const Register kResultTypeReg = RAX;
142};
143
144// Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
145struct TypeTestABI {
146 static const Register kInstanceReg = RAX;
147 static const Register kDstTypeReg = RBX;
148 static const Register kInstantiatorTypeArgumentsReg = RDX;
149 static const Register kFunctionTypeArgumentsReg = RCX;
150 static const Register kSubtypeTestCacheReg = R9;
151
152 static const intptr_t kAbiRegisters =
153 (1 << kInstanceReg) | (1 << kDstTypeReg) |
154 (1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
155 (1 << kSubtypeTestCacheReg);
156
157 // For call to InstanceOfStub.
158 static const Register kResultReg = RAX;
159};
160
161// ABI for InitStaticFieldStub.
162struct InitStaticFieldABI {
163 static const Register kFieldReg = RAX;
164 static const Register kResultReg = RAX;
165};
166
167// ABI for InitInstanceFieldStub.
168struct InitInstanceFieldABI {
169 static const Register kInstanceReg = RBX;
170 static const Register kFieldReg = RDX;
171 static const Register kResultReg = RAX;
172};
173
174// Registers used inside the implementation of InitLateInstanceFieldStub.
175struct InitLateInstanceFieldInternalRegs {
176 static const Register kFunctionReg = RAX;
177 static const Register kAddressReg = RCX;
178 static const Register kScratchReg = RSI;
179};
180
181// ABI for ThrowStub.
182struct ThrowABI {
183 static const Register kExceptionReg = RAX;
184};
185
186// ABI for ReThrowStub.
187struct ReThrowABI {
188 static const Register kExceptionReg = RAX;
189 static const Register kStackTraceReg = RBX;
190};
191
192// ABI for AssertBooleanStub.
193struct AssertBooleanABI {
194 static const Register kObjectReg = RAX;
195};
196
197// ABI for RangeErrorStub.
198struct RangeErrorABI {
199 static const Register kLengthReg = RAX;
200 static const Register kIndexReg = RBX;
201};
202
203// ABI for AllocateMint*Stub.
204struct AllocateMintABI {
205 static const Register kResultReg = RAX;
206 static const Register kTempReg = RBX;
207};
208
209// Registers used inside the implementation of type testing stubs.
210struct TTSInternalRegs {
211 static const Register kInstanceTypeArgumentsReg = RSI;
212 static const Register kScratchReg = R8;
213
214 static const intptr_t kInternalRegisters =
215 (1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg);
216};
217
218// TODO(regis): Add ABIs for type testing stubs and is-type test stubs instead
219// of reusing the constants of the instantiation stubs ABI.
220
221typedef uint32_t RegList;
222const RegList kAllCpuRegistersList = 0xFFFF;
223const RegList kAllFpuRegistersList = 0xFFFF;
224
225const RegList kReservedCpuRegisters =
226 (1 << SPREG) | (1 << FPREG) | (1 << TMP) | (1 << PP) | (1 << THR);
227constexpr intptr_t kNumberOfReservedCpuRegisters = 5;
228// CPU registers available to Dart allocator.
229const RegList kDartAvailableCpuRegs =
230 kAllCpuRegistersList & ~kReservedCpuRegisters;
231constexpr int kNumberOfDartAvailableCpuRegs =
232 kNumberOfCpuRegisters - kNumberOfReservedCpuRegisters;
233constexpr int kStoreBufferWrapperSize = 13;
234
235enum ScaleFactor {
236 TIMES_1 = 0,
237 TIMES_2 = 1,
238 TIMES_4 = 2,
239 TIMES_8 = 3,
240 // Note that Intel addressing does not support this addressing.
241 // > Scale factor — A value of 2, 4, or 8 that is multiplied by the index
242 // > value.
243 // https://software.intel.com/en-us/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4
244 // 3.7.5 Specifying an Offset
245 TIMES_16 = 4,
246 TIMES_HALF_WORD_SIZE = kWordSizeLog2 - 1
247};
248
249#define R(reg) (1 << (reg))
250
251class CallingConventions {
252 public:
253#if defined(TARGET_OS_WINDOWS)
254 static const Register kArg1Reg = RCX;
255 static const Register kArg2Reg = RDX;
256 static const Register kArg3Reg = R8;
257 static const Register kArg4Reg = R9;
258 static const Register ArgumentRegisters[];
259 static const intptr_t kArgumentRegisters =
260 R(kArg1Reg) | R(kArg2Reg) | R(kArg3Reg) | R(kArg4Reg);
261 static const intptr_t kNumArgRegs = 4;
262
263 static const XmmRegister FpuArgumentRegisters[];
264 static const intptr_t kFpuArgumentRegisters =
265 R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3);
266 static const intptr_t kNumFpuArgRegs = 4;
267
268 // can ArgumentRegisters[i] and XmmArgumentRegisters[i] both be used at the
269 // same time? (Windows no, rest yes)
270 static const bool kArgumentIntRegXorFpuReg = true;
271
272 static const intptr_t kShadowSpaceBytes = 4 * kWordSize;
273
274 static const intptr_t kVolatileCpuRegisters =
275 R(RAX) | R(RCX) | R(RDX) | R(R8) | R(R9) | R(R10) | R(R11);
276
277 static const intptr_t kVolatileXmmRegisters =
278 R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3) | R(XMM4) | R(XMM5);
279
280 static const intptr_t kCalleeSaveCpuRegisters =
281 R(RBX) | R(RSI) | R(RDI) | R(R12) | R(R13) | R(R14) | R(R15);
282
283 static const intptr_t kCalleeSaveXmmRegisters =
284 R(XMM6) | R(XMM7) | R(XMM8) | R(XMM9) | R(XMM10) | R(XMM11) | R(XMM12) |
285 R(XMM13) | R(XMM14) | R(XMM15);
286
287 static const XmmRegister xmmFirstNonParameterReg = XMM4;
288
289 // Windows x64 ABI specifies that small objects are passed in registers.
290 // Otherwise they are passed by reference.
291 static const size_t kRegisterTransferLimit = 16;
292
293 static constexpr Register kReturnReg = RAX;
294 static constexpr Register kSecondReturnReg = kNoRegister;
295 static constexpr FpuRegister kReturnFpuReg = XMM0;
296
297 // Whether larger than wordsize arguments are aligned to even registers.
298 static constexpr AlignmentStrategy kArgumentRegisterAlignment =
299 kAlignedToWordSize;
300
301 // How stack arguments are aligned.
302 static constexpr AlignmentStrategy kArgumentStackAlignment =
303 kAlignedToWordSize;
304
305 // How fields in composites are aligned.
306 static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
307
308 // Whether 1 or 2 byte-sized arguments or return values are passed extended
309 // to 4 bytes.
310 static constexpr ExtensionStrategy kReturnRegisterExtension = kNotExtended;
311 static constexpr ExtensionStrategy kArgumentRegisterExtension = kNotExtended;
312 static constexpr ExtensionStrategy kArgumentStackExtension = kNotExtended;
313
314#else
315 static const Register kArg1Reg = RDI;
316 static const Register kArg2Reg = RSI;
317 static const Register kArg3Reg = RDX;
318 static const Register kArg4Reg = RCX;
319 static const Register kArg5Reg = R8;
320 static const Register kArg6Reg = R9;
321 static const Register ArgumentRegisters[];
322 static const intptr_t kArgumentRegisters = R(kArg1Reg) | R(kArg2Reg) |
323 R(kArg3Reg) | R(kArg4Reg) |
324 R(kArg5Reg) | R(kArg6Reg);
325 static const intptr_t kNumArgRegs = 6;
326
327 static const XmmRegister FpuArgumentRegisters[];
328 static const intptr_t kFpuArgumentRegisters = R(XMM0) | R(XMM1) | R(XMM2) |
329 R(XMM3) | R(XMM4) | R(XMM5) |
330 R(XMM6) | R(XMM7);
331 static const intptr_t kNumFpuArgRegs = 8;
332
333 // can ArgumentRegisters[i] and XmmArgumentRegisters[i] both be used at the
334 // same time? (Windows no, rest yes)
335 static const bool kArgumentIntRegXorFpuReg = false;
336
337 static const intptr_t kShadowSpaceBytes = 0;
338
339 static const intptr_t kVolatileCpuRegisters = R(RAX) | R(RCX) | R(RDX) |
340 R(RSI) | R(RDI) | R(R8) |
341 R(R9) | R(R10) | R(R11);
342
343 static const intptr_t kVolatileXmmRegisters =
344 R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3) | R(XMM4) | R(XMM5) | R(XMM6) |
345 R(XMM7) | R(XMM8) | R(XMM9) | R(XMM10) | R(XMM11) | R(XMM12) | R(XMM13) |
346 R(XMM14) | R(XMM15);
347
348 static const intptr_t kCalleeSaveCpuRegisters =
349 R(RBX) | R(R12) | R(R13) | R(R14) | R(R15);
350
351 static const intptr_t kCalleeSaveXmmRegisters = 0;
352
353 static const XmmRegister xmmFirstNonParameterReg = XMM8;
354
355 static constexpr Register kReturnReg = RAX;
356 static constexpr Register kSecondReturnReg = kNoRegister;
357 static constexpr FpuRegister kReturnFpuReg = XMM0;
358
359 // Whether larger than wordsize arguments are aligned to even registers.
360 static constexpr AlignmentStrategy kArgumentRegisterAlignment =
361 kAlignedToWordSize;
362
363 // How stack arguments are aligned.
364 static constexpr AlignmentStrategy kArgumentStackAlignment =
365 kAlignedToWordSize;
366
367 // How fields in composites are aligned.
368 static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
369
370 // Whether 1 or 2 byte-sized arguments or return values are passed extended
371 // to 4 bytes.
372 // Note that `kReturnRegisterExtension != kArgumentRegisterExtension`, which
373 // effectively means that the caller is responsable for truncating and
374 // extending both arguments and return value.
375 static constexpr ExtensionStrategy kReturnRegisterExtension = kNotExtended;
376 static constexpr ExtensionStrategy kArgumentRegisterExtension = kExtendedTo4;
377 static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo4;
378
379#endif
380
381 COMPILE_ASSERT((kArgumentRegisters & kReservedCpuRegisters) == 0);
382
383 static constexpr Register kFirstCalleeSavedCpuReg = RBX;
384 static constexpr Register kFirstNonArgumentRegister = RAX;
385 static constexpr Register kSecondNonArgumentRegister = RBX;
386 static constexpr Register kStackPointerRegister = SPREG;
387
388 COMPILE_ASSERT(((R(kFirstCalleeSavedCpuReg)) & kCalleeSaveCpuRegisters) != 0);
389
390 COMPILE_ASSERT(((R(kFirstNonArgumentRegister) |
391 R(kSecondNonArgumentRegister)) &
392 kArgumentRegisters) == 0);
393};
394
395#undef R
396
397class Instr {
398 public:
399 static const uint8_t kHltInstruction = 0xF4;
400 // We prefer not to use the int3 instruction since it conflicts with gdb.
401 static const uint8_t kBreakPointInstruction = kHltInstruction;
402 static const int kBreakPointInstructionSize = 1;
403 static const uint8_t kGdbBreakpointInstruction = 0xcc;
404
405 bool IsBreakPoint() {
406 ASSERT(kBreakPointInstructionSize == 1);
407 return (*reinterpret_cast<const uint8_t*>(this)) == kBreakPointInstruction;
408 }
409
410 // Instructions are read out of a code stream. The only way to get a
411 // reference to an instruction is to convert a pointer. There is no way
412 // to allocate or create instances of class Instr.
413 // Use the At(pc) function to create references to Instr.
414 static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
415
416 private:
417 DISALLOW_ALLOCATION();
418 // We need to prevent the creation of instances of class Instr.
419 DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
420};
421
422// The largest multibyte nop we will emit. This could go up to 15 if it
423// becomes important to us.
424const int MAX_NOP_SIZE = 8;
425
426const uword kBreakInstructionFiller = 0xCCCCCCCCCCCCCCCCL;
427
428} // namespace dart
429
430#endif // RUNTIME_VM_CONSTANTS_X64_H_
431