51d1c8923a
This is a reland of commit 88496ba1c3
Fixes on top of the original change:
* Closure layout is changed to avoid gap between fixed fields and
variable-length elements on compressed pointers architecture.
This gap was causing crashes in the GC when scanning closure
objects.
* pkg/vm_snapshot_analysis/test/instruction_sizes_test is fixed
on arm64 by decreasing threshold for detecting size changes.
Original change's description:
> [vm,dart2bytecode,modular_aot] Variable-length closure objects
>
> Extend closure objects with variable number of elements to capture.
> This is needed to support capturing multiple independent contexts
> after capturing is computed in the front-end.
>
> The following fixed Closure fields are moved into variable-length
> elements:
> - delayed type arguments;
> - instantiator type arguments;
> - function type arguments;
> - context.
>
> Number of elements and presence/indices of various type arguments
> are encoded into the new length_and_flags field in the Closure.
>
> Most closure objects don't need any of the type arguments so this
> change will reduce average Closure object size.
TEST=ci
Issue: https://github.com/dart-lang/sdk/issues/61572
Issue: https://github.com/dart-lang/sdk/issues/61635
Change-Id: I8685e632e2d0832766ecdc470f3cf9a6b880de48
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/494243
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
746 lines
26 KiB
C++
746 lines
26 KiB
C++
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
||
// for details. All rights reserved. Use of this source code is governed by a
|
||
// BSD-style license that can be found in the LICENSE file.
|
||
|
||
#ifndef RUNTIME_VM_CONSTANTS_X64_H_
|
||
#define RUNTIME_VM_CONSTANTS_X64_H_
|
||
|
||
#ifndef RUNTIME_VM_CONSTANTS_H_
|
||
#error Do not include constants_x64.h directly; use constants.h instead.
|
||
#endif
|
||
|
||
#include "platform/assert.h"
|
||
#include "platform/globals.h"
|
||
#include "platform/utils.h"
|
||
|
||
#include "vm/constants_base.h"
|
||
|
||
namespace dart {
|
||
|
||
#define R(reg) (static_cast<RegList>(1) << (reg))
|
||
|
||
enum Register {
|
||
RAX = 0,
|
||
RCX = 1,
|
||
RDX = 2,
|
||
RBX = 3,
|
||
RSP = 4, // SP
|
||
RBP = 5, // FP
|
||
RSI = 6,
|
||
RDI = 7,
|
||
R8 = 8,
|
||
R9 = 9,
|
||
R10 = 10,
|
||
R11 = 11, // TMP
|
||
R12 = 12, // CODE_REG
|
||
R13 = 13,
|
||
R14 = 14, // THR
|
||
R15 = 15, // PP
|
||
kNumberOfCpuRegisters = 16,
|
||
kNoRegister = -1, // Signals an illegal register.
|
||
};
|
||
|
||
enum ByteRegister {
|
||
AL = 0,
|
||
CL = 1,
|
||
DL = 2,
|
||
BL = 3,
|
||
AH = 4,
|
||
CH = 5,
|
||
DH = 6,
|
||
BH = 7,
|
||
SPL = 4 | 0x10,
|
||
BPL = 5 | 0x10,
|
||
SIL = 6 | 0x10,
|
||
DIL = 7 | 0x10,
|
||
R8B = 8,
|
||
R9B = 9,
|
||
R10B = 10,
|
||
R11B = 11,
|
||
R12B = 12,
|
||
R13B = 13,
|
||
R14B = 14,
|
||
R15B = 15,
|
||
kNumberOfByteRegisters = 16,
|
||
kNoByteRegister = -1 // Signals an illegal register.
|
||
};
|
||
|
||
inline ByteRegister ByteRegisterOf(Register reg) {
|
||
if (RSP <= reg && reg <= RDI) {
|
||
return static_cast<ByteRegister>(reg | 0x10);
|
||
} else {
|
||
return static_cast<ByteRegister>(reg);
|
||
}
|
||
}
|
||
|
||
enum XmmRegister {
|
||
XMM0 = 0,
|
||
XMM1 = 1,
|
||
XMM2 = 2,
|
||
XMM3 = 3,
|
||
XMM4 = 4,
|
||
XMM5 = 5,
|
||
XMM6 = 6,
|
||
XMM7 = 7,
|
||
XMM8 = 8,
|
||
XMM9 = 9,
|
||
XMM10 = 10,
|
||
XMM11 = 11,
|
||
XMM12 = 12,
|
||
XMM13 = 13,
|
||
XMM14 = 14,
|
||
XMM15 = 15,
|
||
kNumberOfXmmRegisters = 16,
|
||
kNoXmmRegister = -1 // Signals an illegal register.
|
||
};
|
||
|
||
// Architecture independent aliases.
|
||
typedef XmmRegister FpuRegister;
|
||
const FpuRegister FpuTMP = XMM15;
|
||
const int kFpuRegisterSize = 16;
|
||
typedef simd128_value_t fpu_register_t;
|
||
const int kNumberOfFpuRegisters = kNumberOfXmmRegisters;
|
||
const FpuRegister kNoFpuRegister = kNoXmmRegister;
|
||
|
||
extern const char* const cpu_reg_names[kNumberOfCpuRegisters];
|
||
extern const char* const cpu_reg_abi_names[kNumberOfCpuRegisters];
|
||
extern const char* const cpu_reg_byte_names[kNumberOfByteRegisters];
|
||
extern const char* const fpu_reg_names[kNumberOfXmmRegisters];
|
||
|
||
enum RexBits {
|
||
REX_NONE = 0,
|
||
REX_B = 1 << 0,
|
||
REX_X = 1 << 1,
|
||
REX_R = 1 << 2,
|
||
REX_W = 1 << 3,
|
||
REX_PREFIX = 1 << 6
|
||
};
|
||
|
||
// Register aliases.
|
||
const Register TMP = R11; // Used as scratch register by the assembler.
|
||
const Register TMP2 = kNoRegister; // No second assembler scratch register.
|
||
// Caches object pool pointer in generated code.
|
||
const Register PP = R15;
|
||
const Register SPREG = RSP; // Stack pointer register.
|
||
const Register FPREG = RBP; // Frame pointer register.
|
||
const Register IC_DATA_REG = RBX; // ICData/MegamorphicCache register.
|
||
const Register ARGS_DESC_REG = R10; // Arguments descriptor register.
|
||
const Register CODE_REG = R12;
|
||
// Set when calling Dart functions in JIT mode, used by LazyCompileStub.
|
||
const Register FUNCTION_REG = RAX;
|
||
const Register THR = R14; // Caches current thread in generated code.
|
||
const Register CALLEE_SAVED_TEMP = RBX;
|
||
|
||
// ABI for catch-clause entry point.
|
||
const Register kExceptionObjectReg = RAX;
|
||
const Register kStackTraceObjectReg = RDX;
|
||
|
||
// ABI for write barrier stub.
|
||
const Register kWriteBarrierObjectReg = RDX;
|
||
const Register kWriteBarrierValueReg = RAX;
|
||
const Register kWriteBarrierSlotReg = R13;
|
||
|
||
// Common ABI for shared slow path stubs.
|
||
struct SharedSlowPathStubABI {
|
||
static constexpr Register kResultReg = RAX;
|
||
};
|
||
|
||
// ABI for instantiation stubs.
|
||
struct InstantiationABI {
|
||
static constexpr Register kUninstantiatedTypeArgumentsReg = RBX;
|
||
static constexpr Register kInstantiatorTypeArgumentsReg = RDX;
|
||
static constexpr Register kFunctionTypeArgumentsReg = RCX;
|
||
static constexpr Register kResultTypeArgumentsReg = RAX;
|
||
static constexpr Register kResultTypeReg = RAX;
|
||
static constexpr Register kScratchReg = R9;
|
||
};
|
||
|
||
// Registers in addition to those listed in InstantiationABI used inside the
|
||
// implementation of the InstantiateTypeArguments stubs.
|
||
struct InstantiateTAVInternalRegs {
|
||
// The set of registers that must be pushed/popped when probing a hash-based
|
||
// cache due to overlap with the registers in InstantiationABI.
|
||
static constexpr intptr_t kSavedRegisters = 0;
|
||
|
||
// Additional registers used to probe hash-based caches.
|
||
static constexpr Register kEntryStartReg = R10;
|
||
static constexpr Register kProbeMaskReg = R13;
|
||
static constexpr Register kProbeDistanceReg = R8;
|
||
static constexpr Register kCurrentEntryIndexReg = RSI;
|
||
};
|
||
|
||
// Registers in addition to those listed in TypeTestABI used inside the
|
||
// implementation of type testing stubs that are _not_ preserved.
|
||
struct TTSInternalRegs {
|
||
static constexpr Register kInstanceTypeArgumentsReg = RSI;
|
||
static constexpr Register kScratchReg = R8;
|
||
static constexpr Register kSubTypeArgumentReg = R10;
|
||
static constexpr Register kSuperTypeArgumentReg = R13;
|
||
|
||
// Must be pushed/popped whenever generic type arguments are being checked as
|
||
// they overlap with registers in TypeTestABI.
|
||
static constexpr intptr_t kSavedTypeArgumentRegisters = 0;
|
||
|
||
static constexpr intptr_t kInternalRegisters =
|
||
((1 << kInstanceTypeArgumentsReg) | (1 << kScratchReg) |
|
||
(1 << kSubTypeArgumentReg) | (1 << kSuperTypeArgumentReg)) &
|
||
~kSavedTypeArgumentRegisters;
|
||
};
|
||
|
||
// Registers in addition to those listed in TypeTestABI used inside the
|
||
// implementation of subtype test cache stubs that are _not_ preserved.
|
||
struct STCInternalRegs {
|
||
static constexpr Register kCacheEntryReg = RDI;
|
||
static constexpr Register kInstanceCidOrSignatureReg = R10;
|
||
static constexpr Register kInstanceInstantiatorTypeArgumentsReg = R13;
|
||
|
||
static constexpr intptr_t kInternalRegisters =
|
||
(1 << kCacheEntryReg) | (1 << kInstanceCidOrSignatureReg) |
|
||
(1 << kInstanceInstantiatorTypeArgumentsReg);
|
||
};
|
||
|
||
// Calling convention when calling TypeTestingStub and SubtypeTestCacheStub.
|
||
struct TypeTestABI {
|
||
static constexpr Register kInstanceReg = RAX;
|
||
static constexpr Register kDstTypeReg = RBX;
|
||
static constexpr Register kInstantiatorTypeArgumentsReg = RDX;
|
||
static constexpr Register kFunctionTypeArgumentsReg = RCX;
|
||
static constexpr Register kSubtypeTestCacheReg = R9;
|
||
static constexpr Register kScratchReg = RSI;
|
||
|
||
// For calls to InstanceOfStub.
|
||
static constexpr Register kInstanceOfResultReg = kInstanceReg;
|
||
// For calls to SubtypeNTestCacheStub. Must not overlap with any other
|
||
// registers above, for it is also used internally as kNullReg in those stubs.
|
||
static constexpr Register kSubtypeTestCacheResultReg = R8;
|
||
|
||
static constexpr intptr_t kPreservedAbiRegisters =
|
||
(1 << kInstanceReg) | (1 << kDstTypeReg) |
|
||
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg);
|
||
|
||
static constexpr intptr_t kNonPreservedAbiRegisters =
|
||
TTSInternalRegs::kInternalRegisters |
|
||
STCInternalRegs::kInternalRegisters | (1 << kSubtypeTestCacheReg) |
|
||
(1 << kScratchReg) | (1 << kSubtypeTestCacheResultReg) | (1 << CODE_REG);
|
||
|
||
static constexpr intptr_t kAbiRegisters =
|
||
kPreservedAbiRegisters | kNonPreservedAbiRegisters;
|
||
};
|
||
|
||
// Calling convention when calling AssertSubtypeStub.
|
||
struct AssertSubtypeABI {
|
||
static constexpr Register kSubTypeReg = RAX;
|
||
static constexpr Register kSuperTypeReg = RBX;
|
||
static constexpr Register kInstantiatorTypeArgumentsReg = RDX;
|
||
static constexpr Register kFunctionTypeArgumentsReg = RCX;
|
||
static constexpr Register kDstNameReg = R9;
|
||
|
||
static constexpr intptr_t kAbiRegisters =
|
||
(1 << kSubTypeReg) | (1 << kSuperTypeReg) |
|
||
(1 << kInstantiatorTypeArgumentsReg) | (1 << kFunctionTypeArgumentsReg) |
|
||
(1 << kDstNameReg);
|
||
|
||
// No result register, as AssertSubtype is only run for side effect
|
||
// (throws if the subtype check fails).
|
||
};
|
||
|
||
// ABI for InitStaticFieldStub.
|
||
struct InitStaticFieldABI {
|
||
static constexpr Register kFieldReg = RDX;
|
||
static constexpr Register kResultReg = RAX;
|
||
};
|
||
|
||
// Registers used inside the implementation of InitLateStaticFieldStub.
|
||
struct InitLateStaticFieldInternalRegs {
|
||
static constexpr Register kAddressReg = RCX;
|
||
static constexpr Register kScratchReg = RSI;
|
||
};
|
||
|
||
// ABI for InitInstanceFieldStub.
|
||
struct InitInstanceFieldABI {
|
||
static constexpr Register kInstanceReg = RBX;
|
||
static constexpr Register kFieldReg = RDX;
|
||
static constexpr Register kResultReg = RAX;
|
||
};
|
||
|
||
// Registers used inside the implementation of InitLateInstanceFieldStub.
|
||
struct InitLateInstanceFieldInternalRegs {
|
||
static constexpr Register kAddressReg = RCX;
|
||
static constexpr Register kScratchReg = RSI;
|
||
};
|
||
|
||
// ABI for LateInitializationError stubs.
|
||
struct LateInitializationErrorABI {
|
||
static constexpr Register kFieldReg = RSI;
|
||
};
|
||
|
||
// ABI for FieldAccessError stubs.
|
||
struct FieldAccessErrorABI {
|
||
static constexpr Register kFieldReg = RSI;
|
||
};
|
||
|
||
// ABI for ThrowStub.
|
||
struct ThrowABI {
|
||
static constexpr Register kExceptionReg = RAX;
|
||
};
|
||
|
||
// ABI for ReThrowStub.
|
||
struct ReThrowABI {
|
||
static constexpr Register kExceptionReg = RAX;
|
||
static constexpr Register kStackTraceReg = RBX;
|
||
};
|
||
|
||
// ABI for RangeErrorStub.
|
||
struct RangeErrorABI {
|
||
static constexpr Register kLengthReg = RAX;
|
||
static constexpr Register kIndexReg = RBX;
|
||
};
|
||
|
||
// ABI for AllocateObjectStub.
|
||
struct AllocateObjectABI {
|
||
static constexpr Register kResultReg = RAX;
|
||
static constexpr Register kTypeArgumentsReg = RDX;
|
||
static constexpr Register kTagsReg = R8;
|
||
};
|
||
|
||
// ABI for AllocateClosureStub.
|
||
struct AllocateClosureABI {
|
||
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
|
||
static constexpr Register kFunctionReg = RBX;
|
||
static constexpr Register kLengthAndFlagsReg = RDX;
|
||
static constexpr Register kContextReg = RCX;
|
||
static constexpr Register kScratchReg = R13;
|
||
};
|
||
|
||
// ABI for AllocateMintShared*Stub.
|
||
struct AllocateMintABI {
|
||
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
|
||
static constexpr Register kTempReg = RBX;
|
||
};
|
||
|
||
// ABI for Allocate{Mint,Double,Float32x4,Float64x2}Stub.
|
||
struct AllocateBoxABI {
|
||
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
|
||
static constexpr Register kTempReg = RBX;
|
||
};
|
||
|
||
// ABI for AllocateArrayStub.
|
||
struct AllocateArrayABI {
|
||
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
|
||
static constexpr Register kLengthReg = R10;
|
||
static constexpr Register kTypeArgumentsReg = RBX;
|
||
};
|
||
|
||
// ABI for AllocateRecordStub.
|
||
struct AllocateRecordABI {
|
||
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
|
||
static constexpr Register kShapeReg = RBX;
|
||
static constexpr Register kTemp1Reg = RDX;
|
||
static constexpr Register kTemp2Reg = RCX;
|
||
};
|
||
|
||
// ABI for AllocateSmallRecordStub (AllocateRecord2, AllocateRecord2Named,
|
||
// AllocateRecord3, AllocateRecord3Named).
|
||
struct AllocateSmallRecordABI {
|
||
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
|
||
static constexpr Register kShapeReg = R10;
|
||
static constexpr Register kValue0Reg = RBX;
|
||
static constexpr Register kValue1Reg = RDX;
|
||
static constexpr Register kValue2Reg = RCX;
|
||
static constexpr Register kTempReg = RDI;
|
||
};
|
||
|
||
// ABI for AllocateTypedDataArrayStub.
|
||
struct AllocateTypedDataArrayABI {
|
||
static constexpr Register kResultReg = AllocateObjectABI::kResultReg;
|
||
static constexpr Register kLengthReg = kResultReg;
|
||
};
|
||
|
||
// ABI for BoxDoubleStub.
|
||
struct BoxDoubleStubABI {
|
||
static constexpr FpuRegister kValueReg = XMM0;
|
||
static constexpr Register kTempReg = RBX;
|
||
static constexpr Register kResultReg = RAX;
|
||
};
|
||
|
||
// ABI for DoubleToIntegerStub.
|
||
struct DoubleToIntegerStubABI {
|
||
static constexpr FpuRegister kInputReg = XMM0;
|
||
static constexpr Register kRecognizedKindReg = RAX;
|
||
static constexpr Register kResultReg = RAX;
|
||
};
|
||
|
||
// ABI for CheckedStoreIntoSharedStub.
|
||
struct CheckedStoreIntoSharedStubABI {
|
||
static constexpr Register kFieldReg = RBX;
|
||
static constexpr Register kValueReg = RDX;
|
||
static constexpr Register kResultReg = RAX;
|
||
};
|
||
|
||
// ABI for EnsureDeeplyImmutableStub.
|
||
struct EnsureDeeplyImmutableStubABI {
|
||
static constexpr Register kValueReg = RAX;
|
||
static constexpr Register kTempReg = R10;
|
||
};
|
||
|
||
// ABI for SuspendStub (AwaitStub, AwaitWithTypeCheckStub, YieldAsyncStarStub,
|
||
// SuspendSyncStarAtStartStub, SuspendSyncStarAtYieldStub).
|
||
struct SuspendStubABI {
|
||
static constexpr Register kArgumentReg = RAX;
|
||
static constexpr Register kTypeArgsReg = RDX; // Can be the same as kTempReg
|
||
static constexpr Register kTempReg = RDX;
|
||
static constexpr Register kFrameSizeReg = RCX;
|
||
static constexpr Register kSuspendStateReg = RBX;
|
||
static constexpr Register kFunctionDataReg = R8;
|
||
static constexpr Register kSrcFrameReg = RSI;
|
||
static constexpr Register kDstFrameReg = RDI;
|
||
|
||
// Number of bytes to skip after
|
||
// suspend stub return address in order to resume.
|
||
// X64: mov rsp, rbp; pop rbp; ret
|
||
static constexpr intptr_t kResumePcDistance = 5;
|
||
};
|
||
|
||
// ABI for InitSuspendableFunctionStub (InitAsyncStub, InitAsyncStarStub,
|
||
// InitSyncStarStub).
|
||
struct InitSuspendableFunctionStubABI {
|
||
static constexpr Register kTypeArgsReg = RAX;
|
||
};
|
||
|
||
// ABI for ResumeStub
|
||
struct ResumeStubABI {
|
||
static constexpr Register kSuspendStateReg = RBX;
|
||
static constexpr Register kTempReg = RDX;
|
||
// Registers for the frame copying (the 1st part).
|
||
static constexpr Register kFrameSizeReg = RCX;
|
||
static constexpr Register kSrcFrameReg = RSI;
|
||
static constexpr Register kDstFrameReg = RDI;
|
||
// Registers for control transfer.
|
||
// (the 2nd part, can reuse registers from the 1st part)
|
||
static constexpr Register kResumePcReg = RCX;
|
||
// Can also reuse kSuspendStateReg but should not conflict with CODE_REG/PP.
|
||
static constexpr Register kExceptionReg = RSI;
|
||
static constexpr Register kStackTraceReg = RDI;
|
||
};
|
||
|
||
// ABI for ReturnStub (ReturnAsyncStub, ReturnAsyncNotFutureStub,
|
||
// ReturnAsyncStarStub).
|
||
struct ReturnStubABI {
|
||
static constexpr Register kSuspendStateReg = RBX;
|
||
};
|
||
|
||
// ABI for AsyncExceptionHandlerStub.
|
||
struct AsyncExceptionHandlerStubABI {
|
||
static constexpr Register kSuspendStateReg = RBX;
|
||
};
|
||
|
||
// ABI for CloneSuspendStateStub.
|
||
struct CloneSuspendStateStubABI {
|
||
static constexpr Register kSourceReg = RAX;
|
||
static constexpr Register kDestinationReg = RBX;
|
||
static constexpr Register kTempReg = RDX;
|
||
static constexpr Register kFrameSizeReg = RCX;
|
||
static constexpr Register kSrcFrameReg = RSI;
|
||
static constexpr Register kDstFrameReg = RDI;
|
||
};
|
||
|
||
// ABI for FfiAsyncCallbackSendStub.
|
||
struct FfiAsyncCallbackSendStubABI {
|
||
static constexpr Register kArgsReg = RAX;
|
||
};
|
||
|
||
// ABI for DispatchTableNullErrorStub and consequently for all dispatch
|
||
// table calls (though normal functions will not expect or use this
|
||
// register). This ABI is added to distinguish memory corruption errors from
|
||
// null errors.
|
||
struct DispatchTableNullErrorABI {
|
||
static constexpr Register kClassIdReg = RCX;
|
||
};
|
||
|
||
typedef uint32_t RegList;
|
||
const RegList kAllCpuRegistersList = 0xFFFF;
|
||
const RegList kAllFpuRegistersList = 0xFFFF;
|
||
|
||
const RegList kReservedCpuRegisters =
|
||
R(SPREG) | R(FPREG) | R(TMP) | R(PP) | R(THR);
|
||
constexpr intptr_t kNumberOfReservedCpuRegisters =
|
||
Utils::CountOneBits32(kReservedCpuRegisters);
|
||
// CPU registers available to Dart allocator.
|
||
const RegList kDartAvailableCpuRegs =
|
||
kAllCpuRegistersList & ~kReservedCpuRegisters;
|
||
constexpr int kNumberOfDartAvailableCpuRegs =
|
||
kNumberOfCpuRegisters - kNumberOfReservedCpuRegisters;
|
||
// Low numbered registers sometimes require fewer prefixes.
|
||
constexpr int kRegisterAllocationBias = 0;
|
||
constexpr int kStoreBufferWrapperSize = 13;
|
||
|
||
#if defined(DART_TARGET_OS_WINDOWS)
|
||
const RegList kAbiPreservedCpuRegs =
|
||
R(RBX) | R(RSI) | R(RDI) | R(R12) | R(R13) | R(R14) | R(R15);
|
||
const RegList kAbiVolatileFpuRegs =
|
||
R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3) | R(XMM4) | R(XMM5);
|
||
#else
|
||
const RegList kAbiPreservedCpuRegs = R(RBX) | R(R12) | R(R13) | R(R14) | R(R15);
|
||
const RegList kAbiVolatileFpuRegs = kAllFpuRegistersList;
|
||
#endif
|
||
|
||
// Registers available to Dart that are not preserved by runtime calls.
|
||
const RegList kDartVolatileCpuRegs =
|
||
kDartAvailableCpuRegs & ~kAbiPreservedCpuRegs;
|
||
const RegList kDartVolatileFpuRegs = kAbiVolatileFpuRegs & ~R(FpuTMP);
|
||
|
||
enum ScaleFactor {
|
||
TIMES_1 = 0,
|
||
TIMES_2 = 1,
|
||
TIMES_4 = 2,
|
||
TIMES_8 = 3,
|
||
// Note that Intel addressing does not support this addressing.
|
||
// > Scale factor — A value of 2, 4, or 8 that is multiplied by the index
|
||
// > value.
|
||
// 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
|
||
// 3.7.5 Specifying an Offset
|
||
TIMES_16 = 4,
|
||
// We can't include vm/compiler/runtime_api.h, so just be explicit instead
|
||
// of using (dart::)kWordSizeLog2.
|
||
#if defined(TARGET_ARCH_IS_64_BIT)
|
||
// Used for Smi-boxed indices.
|
||
TIMES_HALF_WORD_SIZE = kInt64SizeLog2 - 1,
|
||
// Used for unboxed indices.
|
||
TIMES_WORD_SIZE = kInt64SizeLog2,
|
||
#else
|
||
#error "Unexpected word size"
|
||
#endif
|
||
#if !defined(DART_COMPRESSED_POINTERS)
|
||
TIMES_COMPRESSED_WORD_SIZE = TIMES_WORD_SIZE,
|
||
#else
|
||
TIMES_COMPRESSED_WORD_SIZE = TIMES_HALF_WORD_SIZE,
|
||
#endif
|
||
// Used for Smi-boxed indices.
|
||
TIMES_COMPRESSED_HALF_WORD_SIZE = TIMES_COMPRESSED_WORD_SIZE - 1,
|
||
};
|
||
|
||
class CallingConventions {
|
||
public:
|
||
#if defined(DART_TARGET_OS_WINDOWS)
|
||
static constexpr Register kArg1Reg = RCX;
|
||
static constexpr Register kArg2Reg = RDX;
|
||
static constexpr Register kArg3Reg = R8;
|
||
static constexpr Register kArg4Reg = R9;
|
||
static const Register ArgumentRegisters[];
|
||
static constexpr intptr_t kArgumentRegisters =
|
||
R(kArg1Reg) | R(kArg2Reg) | R(kArg3Reg) | R(kArg4Reg);
|
||
static constexpr intptr_t kNumArgRegs = 4;
|
||
static constexpr Register kPointerToReturnStructRegisterCall = kArg1Reg;
|
||
|
||
static const XmmRegister FpuArgumentRegisters[];
|
||
static constexpr intptr_t kFpuArgumentRegisters =
|
||
R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3);
|
||
static constexpr intptr_t kNumFpuArgRegs = 4;
|
||
|
||
// Whether ArgumentRegisters[i] prevents using XmmArgumentRegisters[i] at the
|
||
// same time and vice versa.
|
||
static constexpr bool kArgumentIntRegXorFpuReg = true;
|
||
|
||
// AL not set on vararg calls in Windows.
|
||
static constexpr Register kVarArgFpuRegisterCount = kNoRegister;
|
||
|
||
// > The x64 Application Binary Interface (ABI) uses a four-register
|
||
// > fast-call calling convention by default. Space is allocated on the call
|
||
// > stack as a shadow store for callees to save those registers.
|
||
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-160
|
||
//
|
||
// The caller allocates this space. The caller should also reclaim this space
|
||
// after the call to restore the stack to its original state if needed.
|
||
//
|
||
// This is also known as home space.
|
||
// https://devblogs.microsoft.com/oldnewthing/20160623-00/?p=93735
|
||
static constexpr intptr_t kShadowSpaceBytes = 4 * kWordSize;
|
||
|
||
static constexpr intptr_t kVolatileCpuRegisters =
|
||
R(RAX) | R(RCX) | R(RDX) | R(R8) | R(R9) | R(R10) | R(R11);
|
||
|
||
static constexpr RegList kVolatileXmmRegisters = kAbiVolatileFpuRegs;
|
||
|
||
static constexpr intptr_t kCalleeSaveXmmRegisters =
|
||
R(XMM6) | R(XMM7) | R(XMM8) | R(XMM9) | R(XMM10) | R(XMM11) | R(XMM12) |
|
||
R(XMM13) | R(XMM14) | R(XMM15);
|
||
|
||
static constexpr XmmRegister xmmFirstNonParameterReg = XMM4;
|
||
|
||
// Windows x64 ABI specifies that small objects are passed in registers.
|
||
// Otherwise they are passed by reference.
|
||
static const size_t kRegisterTransferLimit = 16;
|
||
|
||
static constexpr Register kReturnReg = RAX;
|
||
static constexpr Register kSecondReturnReg = RDX;
|
||
static constexpr FpuRegister kReturnFpuReg = XMM0;
|
||
static constexpr FpuRegister kSecondReturnFpuReg = XMM1;
|
||
static constexpr Register kPointerToReturnStructRegisterReturn = kReturnReg;
|
||
|
||
// Whether larger than wordsize arguments are aligned to even registers.
|
||
static constexpr AlignmentStrategy kArgumentRegisterAlignment =
|
||
kAlignedToWordSize;
|
||
static constexpr AlignmentStrategy kArgumentRegisterAlignmentVarArgs =
|
||
kArgumentRegisterAlignment;
|
||
|
||
// How stack arguments are aligned.
|
||
static constexpr AlignmentStrategy kArgumentStackAlignment =
|
||
kAlignedToWordSize;
|
||
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
|
||
kArgumentStackAlignment;
|
||
|
||
// How fields in compounds are aligned.
|
||
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
|
||
|
||
// Whether 1 or 2 byte-sized arguments or return values are passed extended
|
||
// to 4 bytes.
|
||
static constexpr ExtensionStrategy kReturnRegisterExtension = kNotExtended;
|
||
static constexpr ExtensionStrategy kArgumentRegisterExtension = kNotExtended;
|
||
static constexpr ExtensionStrategy kArgumentStackExtension = kNotExtended;
|
||
|
||
#else
|
||
static constexpr Register kArg1Reg = RDI;
|
||
static constexpr Register kArg2Reg = RSI;
|
||
static constexpr Register kArg3Reg = RDX;
|
||
static constexpr Register kArg4Reg = RCX;
|
||
static constexpr Register kArg5Reg = R8;
|
||
static constexpr Register kArg6Reg = R9;
|
||
static const Register ArgumentRegisters[];
|
||
static constexpr intptr_t kArgumentRegisters = R(kArg1Reg) | R(kArg2Reg) |
|
||
R(kArg3Reg) | R(kArg4Reg) |
|
||
R(kArg5Reg) | R(kArg6Reg);
|
||
static constexpr intptr_t kNumArgRegs = 6;
|
||
static constexpr Register kPointerToReturnStructRegisterCall = kArg1Reg;
|
||
|
||
static const XmmRegister FpuArgumentRegisters[];
|
||
static constexpr intptr_t kFpuArgumentRegisters =
|
||
R(XMM0) | R(XMM1) | R(XMM2) | R(XMM3) | R(XMM4) | R(XMM5) | R(XMM6) |
|
||
R(XMM7);
|
||
static constexpr intptr_t kNumFpuArgRegs = 8;
|
||
|
||
// Whether ArgumentRegisters[i] prevents using XmmArgumentRegisters[i] at the
|
||
// same time and vice versa.
|
||
static constexpr bool kArgumentIntRegXorFpuReg = false;
|
||
|
||
// > For calls that may call functions that use varargs or stdargs
|
||
// > (prototype-less calls or calls to functions containing ellipsis (...) in
|
||
// > the declaration) %al16 is used as hidden argument to specify the number
|
||
// > of vector registers used. The contents of %al do not need to match
|
||
// > exactly the number of registers, but must be an upper bound on the number
|
||
// > of vector registers used and is in the range 0–8 inclusive.
|
||
// System V ABI spec.
|
||
static constexpr Register kVarArgFpuRegisterCount = RAX;
|
||
|
||
static constexpr intptr_t kShadowSpaceBytes = 0;
|
||
|
||
static constexpr intptr_t kVolatileCpuRegisters = R(RAX) | R(RCX) | R(RDX) |
|
||
R(RSI) | R(RDI) | R(R8) |
|
||
R(R9) | R(R10) | R(R11);
|
||
|
||
static constexpr RegList kVolatileXmmRegisters = kAbiVolatileFpuRegs;
|
||
|
||
static constexpr intptr_t kCalleeSaveXmmRegisters = 0;
|
||
|
||
static constexpr XmmRegister xmmFirstNonParameterReg = XMM8;
|
||
|
||
static constexpr Register kReturnReg = RAX;
|
||
static constexpr Register kSecondReturnReg = RDX;
|
||
static constexpr FpuRegister kReturnFpuReg = XMM0;
|
||
static constexpr FpuRegister kSecondReturnFpuReg = XMM1;
|
||
static constexpr Register kPointerToReturnStructRegisterReturn = kReturnReg;
|
||
|
||
// Whether larger than wordsize arguments are aligned to even registers.
|
||
static constexpr AlignmentStrategy kArgumentRegisterAlignment =
|
||
kAlignedToWordSize;
|
||
static constexpr AlignmentStrategy kArgumentRegisterAlignmentVarArgs =
|
||
kArgumentRegisterAlignment;
|
||
|
||
// How stack arguments are aligned.
|
||
static constexpr AlignmentStrategy kArgumentStackAlignment =
|
||
kAlignedToWordSize;
|
||
static constexpr AlignmentStrategy kArgumentStackAlignmentVarArgs =
|
||
kArgumentStackAlignment;
|
||
|
||
// How fields in compounds are aligned.
|
||
static constexpr AlignmentStrategy kFieldAlignment = kAlignedToValueSize;
|
||
|
||
// Whether 1 or 2 byte-sized arguments or return values are passed extended
|
||
// to 4 bytes.
|
||
// Note that `kReturnRegisterExtension != kArgumentRegisterExtension`, which
|
||
// effectively means that the caller is responsable for truncating and
|
||
// extending both arguments and return value.
|
||
static constexpr ExtensionStrategy kReturnRegisterExtension = kNotExtended;
|
||
static constexpr ExtensionStrategy kArgumentRegisterExtension = kExtendedTo4;
|
||
static constexpr ExtensionStrategy kArgumentStackExtension = kExtendedTo4;
|
||
|
||
#endif
|
||
|
||
static constexpr intptr_t kCalleeSaveCpuRegisters = kAbiPreservedCpuRegs;
|
||
|
||
COMPILE_ASSERT((kArgumentRegisters & kReservedCpuRegisters) == 0);
|
||
|
||
static constexpr Register kFfiAnyNonAbiRegister = R12;
|
||
static constexpr Register kFirstNonArgumentRegister = RAX;
|
||
static constexpr Register kSecondNonArgumentRegister = RBX;
|
||
static constexpr Register kStackPointerRegister = SPREG;
|
||
|
||
COMPILE_ASSERT(((R(kFfiAnyNonAbiRegister)) & kCalleeSaveCpuRegisters) != 0);
|
||
|
||
COMPILE_ASSERT(
|
||
((R(kFirstNonArgumentRegister) | R(kSecondNonArgumentRegister)) &
|
||
(kArgumentRegisters | R(kPointerToReturnStructRegisterCall))) == 0);
|
||
};
|
||
|
||
// Register based calling convention used for Dart functions.
|
||
//
|
||
// See |compiler::ComputeCallingConvention| for more details.
|
||
struct DartCallingConvention {
|
||
static constexpr Register kCpuRegistersForArgs[] = {RDI, RSI, RDX,
|
||
RBX, R8, R9};
|
||
static constexpr FpuRegister kFpuRegistersForArgs[] = {XMM1, XMM2, XMM3,
|
||
XMM4, XMM5, XMM6};
|
||
};
|
||
|
||
#undef R
|
||
|
||
class Instr {
|
||
public:
|
||
static constexpr uint8_t kHltInstruction = 0xF4;
|
||
// We prefer not to use the int3 instruction since it conflicts with gdb.
|
||
static constexpr uint8_t kBreakPointInstruction = kHltInstruction;
|
||
static constexpr int kBreakPointInstructionSize = 1;
|
||
static constexpr uint8_t kGdbBreakpointInstruction = 0xcc;
|
||
|
||
bool IsBreakPoint() {
|
||
ASSERT(kBreakPointInstructionSize == 1);
|
||
return (*reinterpret_cast<const uint8_t*>(this)) == kBreakPointInstruction;
|
||
}
|
||
|
||
// Instructions are read out of a code stream. The only way to get a
|
||
// reference to an instruction is to convert a pointer. There is no way
|
||
// to allocate or create instances of class Instr.
|
||
// Use the At(pc) function to create references to Instr.
|
||
static Instr* At(uword pc) { return reinterpret_cast<Instr*>(pc); }
|
||
|
||
private:
|
||
DISALLOW_ALLOCATION();
|
||
// We need to prevent the creation of instances of class Instr.
|
||
DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
|
||
};
|
||
|
||
// The largest multibyte nop we will emit. This could go up to 15 if it
|
||
// becomes important to us.
|
||
const int MAX_NOP_SIZE = 8;
|
||
|
||
const uint64_t kBreakInstructionFiller = 0xCCCCCCCCCCCCCCCCL;
|
||
|
||
// Based on presentation "Causes of Performance Instability due to Code
|
||
// Placement in X86 - Zia Ansari, Intel"[1].
|
||
//
|
||
// [1]: https://www.youtube.com/watch?v=IX16gcX4vDQ
|
||
const intptr_t kPreferredLoopAlignment = 32;
|
||
|
||
} // namespace dart
|
||
|
||
#endif // RUNTIME_VM_CONSTANTS_X64_H_
|