[vm, compiler] Update TSAN instrumentation.
TEST=tsan Cq-Include-Trybots: luci.dart.try:vm-tsan-linux-release-x64-try,vm-tsan-linux-release-arm64-try,iso-stress-linux-arm64-try,iso-stress-linux-x64-try Change-Id: I0c49b501c53f9a5117bb14800e342e6fe9b4eba6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/442730 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
Commit Queue
parent
8b97e6c6a4
commit
dc97aa7fb9
@@ -17,8 +17,14 @@
|
||||
|
||||
#if defined(USING_THREAD_SANITIZER)
|
||||
#define NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
|
||||
extern "C" void __tsan_acquire(void* addr);
|
||||
extern "C" void __tsan_release(void* addr);
|
||||
extern "C" void __tsan_atomic32_load(uint32_t* addr, int order);
|
||||
extern "C" void __tsan_atomic32_store(uint32_t* addr,
|
||||
uint32_t value,
|
||||
int order);
|
||||
extern "C" void __tsan_atomic64_load(uint64_t* addr, int order);
|
||||
extern "C" void __tsan_atomic64_store(uint64_t* addr,
|
||||
uint64_t value,
|
||||
int order);
|
||||
#else
|
||||
#define NO_SANITIZE_THREAD
|
||||
#endif
|
||||
|
||||
@@ -286,16 +286,69 @@ void Assembler::Align(intptr_t alignment, intptr_t offset) {
|
||||
ASSERT(((offset + buffer_.GetPosition()) & (alignment - 1)) == 0);
|
||||
}
|
||||
|
||||
void Assembler::TsanLoadAcquire(Register addr) {
|
||||
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
|
||||
void Assembler::TsanLoadAcquire(Register dst, Register addr, OperandSize size) {
|
||||
RegisterSet registers(kDartVolatileCpuRegs & ~(1 << dst),
|
||||
kAllFpuRegistersList);
|
||||
|
||||
EnterFrame(0);
|
||||
PushRegisters(registers);
|
||||
ReserveAlignedFrameSpace(0);
|
||||
|
||||
MoveRegister(R0, addr);
|
||||
rt.Call(kTsanLoadAcquireRuntimeEntry, /*argument_count=*/1);
|
||||
LoadImmediate(R1, __ATOMIC_ACQUIRE);
|
||||
|
||||
mov(CSP, SP);
|
||||
switch (size) {
|
||||
case kEightBytes:
|
||||
ldr(TMP, compiler::Address(
|
||||
THR, kTsanAtomic64LoadRuntimeEntry.OffsetFromThread()));
|
||||
break;
|
||||
case kUnsignedFourBytes:
|
||||
ldr(TMP, compiler::Address(
|
||||
THR, kTsanAtomic32LoadRuntimeEntry.OffsetFromThread()));
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
str(TMP, compiler::Address(THR, target::Thread::vm_tag_offset()));
|
||||
blr(TMP);
|
||||
LoadImmediate(TMP, VMTag::kDartTagId);
|
||||
str(TMP, compiler::Address(THR, target::Thread::vm_tag_offset()));
|
||||
SetupCSPFromThread(THR);
|
||||
|
||||
MoveRegister(dst, R0);
|
||||
|
||||
AddImmediate(SP, FP, -registers.SpillSize());
|
||||
PopRegisters(registers);
|
||||
LeaveFrame();
|
||||
}
|
||||
|
||||
void Assembler::TsanStoreRelease(Register addr) {
|
||||
void Assembler::TsanStoreRelease(Register src,
|
||||
Register addr,
|
||||
OperandSize size) {
|
||||
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
|
||||
MoveRegister(R0, addr);
|
||||
rt.Call(kTsanStoreReleaseRuntimeEntry, /*argument_count=*/1);
|
||||
|
||||
if (src == R0) {
|
||||
MoveRegister(R1, src);
|
||||
MoveRegister(R0, addr);
|
||||
} else {
|
||||
MoveRegister(R0, addr);
|
||||
MoveRegister(R1, src);
|
||||
}
|
||||
LoadImmediate(R2, __ATOMIC_RELEASE);
|
||||
|
||||
switch (size) {
|
||||
case kEightBytes:
|
||||
rt.Call(kTsanAtomic64StoreRuntimeEntry, /*argument_count=*/3);
|
||||
break;
|
||||
case kFourBytes:
|
||||
case kUnsignedFourBytes:
|
||||
rt.Call(kTsanAtomic32StoreRuntimeEntry, /*argument_count=*/3);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int CountLeadingZeros(uint64_t value, int width) {
|
||||
@@ -1779,10 +1832,7 @@ LeafRuntimeScope::~LeafRuntimeScope() {
|
||||
// SP might have been modified to reserve space for arguments
|
||||
// and ensure proper alignment of the stack frame.
|
||||
// We need to restore it before restoring registers.
|
||||
const intptr_t kPushedRegistersSize =
|
||||
kRuntimeCallSavedRegisters.CpuRegisterCount() * target::kWordSize +
|
||||
kRuntimeCallSavedRegisters.FpuRegisterCount() * kFpuRegisterSize;
|
||||
__ AddImmediate(SP, FP, -kPushedRegistersSize);
|
||||
__ AddImmediate(SP, FP, -kRuntimeCallSavedRegisters.SpillSize());
|
||||
__ PopRegisters(kRuntimeCallSavedRegisters);
|
||||
}
|
||||
|
||||
|
||||
@@ -502,8 +502,8 @@ class Assembler : public AssemblerBase {
|
||||
StoreToOffset(src, base, offset, kEightBytes);
|
||||
}
|
||||
|
||||
void TsanLoadAcquire(Register addr);
|
||||
void TsanStoreRelease(Register addr);
|
||||
void TsanLoadAcquire(Register dst, Register addr, OperandSize size);
|
||||
void TsanStoreRelease(Register src, Register addr, OperandSize size);
|
||||
|
||||
void LoadAcquire(Register dst,
|
||||
const Address& address,
|
||||
@@ -515,9 +515,10 @@ class Assembler : public AssemblerBase {
|
||||
AddImmediate(TMP2, src, address.offset());
|
||||
src = TMP2;
|
||||
}
|
||||
ldar(dst, src, size);
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
TsanLoadAcquire(src);
|
||||
TsanLoadAcquire(dst, src, size);
|
||||
} else {
|
||||
ldar(dst, src, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,9 +539,10 @@ class Assembler : public AssemblerBase {
|
||||
AddImmediate(TMP2, dst, address.offset());
|
||||
dst = TMP2;
|
||||
}
|
||||
stlr(src, dst, size);
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
TsanStoreRelease(dst);
|
||||
TsanStoreRelease(src, dst, size);
|
||||
} else {
|
||||
stlr(src, dst, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2880,8 +2880,7 @@ void Assembler::PushRegisters(const RegisterSet& regs) {
|
||||
// The order in which the registers are pushed must match the order
|
||||
// in which the registers are encoded in the safepoint's stack map.
|
||||
|
||||
intptr_t size = (regs.CpuRegisterCount() * target::kWordSize) +
|
||||
(regs.FpuRegisterCount() * kFpuRegisterSize);
|
||||
intptr_t size = regs.SpillSize();
|
||||
if (size == 0) {
|
||||
return; // Skip no-op SP update.
|
||||
}
|
||||
@@ -2909,8 +2908,7 @@ void Assembler::PopRegisters(const RegisterSet& regs) {
|
||||
// The order in which the registers are pushed must match the order
|
||||
// in which the registers are encoded in the safepoint's stack map.
|
||||
|
||||
intptr_t size = (regs.CpuRegisterCount() * target::kWordSize) +
|
||||
(regs.FpuRegisterCount() * kFpuRegisterSize);
|
||||
intptr_t size = regs.SpillSize();
|
||||
if (size == 0) {
|
||||
return; // Skip no-op SP update.
|
||||
}
|
||||
@@ -3084,15 +3082,92 @@ void Assembler::Jump(const Address& address) {
|
||||
jr(TMP2);
|
||||
}
|
||||
|
||||
void Assembler::TsanLoadAcquire(Register addr) {
|
||||
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
|
||||
MoveRegister(A0, addr);
|
||||
rt.Call(kTsanLoadAcquireRuntimeEntry, /*argument_count=*/1);
|
||||
void Assembler::TsanLoadAcquire(Register dst,
|
||||
const Address& addr,
|
||||
OperandSize size) {
|
||||
ASSERT(addr.base() != SP);
|
||||
ASSERT(addr.base() != FP);
|
||||
ASSERT(dst != SP);
|
||||
ASSERT(dst != FP);
|
||||
|
||||
RegisterSet registers(kDartVolatileCpuRegs & ~(1 << dst),
|
||||
kAbiVolatileFpuRegs);
|
||||
|
||||
subi(SP, SP, 4 * target::kWordSize);
|
||||
sx(RA, Address(SP, 3 * target::kWordSize));
|
||||
sx(FP, Address(SP, 2 * target::kWordSize));
|
||||
sx(CODE_REG, Address(SP, 1 * target::kWordSize));
|
||||
sx(PP, Address(SP, 0 * target::kWordSize));
|
||||
addi(FP, SP, 4 * target::kWordSize);
|
||||
|
||||
PushRegisters(registers);
|
||||
ReserveAlignedFrameSpace(0);
|
||||
|
||||
AddImmediate(A0, addr.base(), addr.offset());
|
||||
LoadImmediate(A1, __ATOMIC_ACQUIRE);
|
||||
|
||||
switch (size) {
|
||||
case kEightBytes:
|
||||
lx(TMP2, compiler::Address(
|
||||
THR, kTsanAtomic64LoadRuntimeEntry.OffsetFromThread()));
|
||||
break;
|
||||
case kUnsignedFourBytes:
|
||||
lx(TMP2, compiler::Address(
|
||||
THR, kTsanAtomic32LoadRuntimeEntry.OffsetFromThread()));
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
sx(TMP2, compiler::Address(THR, target::Thread::vm_tag_offset()));
|
||||
jalr(TMP2);
|
||||
LoadImmediate(TMP2, VMTag::kDartTagId);
|
||||
sx(TMP2, compiler::Address(THR, target::Thread::vm_tag_offset()));
|
||||
|
||||
MoveRegister(dst, A0);
|
||||
|
||||
subi(SP, FP, registers.SpillSize() + 4 * target::kWordSize);
|
||||
PopRegisters(registers);
|
||||
|
||||
subi(SP, FP, 4 * target::kWordSize);
|
||||
lx(PP, Address(SP, 0 * target::kWordSize));
|
||||
lx(CODE_REG, Address(SP, 1 * target::kWordSize));
|
||||
lx(FP, Address(SP, 2 * target::kWordSize));
|
||||
lx(RA, Address(SP, 3 * target::kWordSize));
|
||||
addi(SP, SP, 4 * target::kWordSize);
|
||||
}
|
||||
void Assembler::TsanStoreRelease(Register addr) {
|
||||
|
||||
void Assembler::TsanStoreRelease(Register src,
|
||||
const Address& addr,
|
||||
OperandSize size) {
|
||||
ASSERT(addr.base() != SP);
|
||||
ASSERT(addr.base() != FP);
|
||||
ASSERT(src != SP);
|
||||
ASSERT(src != FP);
|
||||
|
||||
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
|
||||
MoveRegister(A0, addr);
|
||||
rt.Call(kTsanStoreReleaseRuntimeEntry, /*argument_count=*/1);
|
||||
|
||||
if (src == A0) {
|
||||
MoveRegister(A1, src);
|
||||
AddImmediate(A0, addr.base(), addr.offset());
|
||||
} else {
|
||||
AddImmediate(A0, addr.base(), addr.offset());
|
||||
MoveRegister(A1, src);
|
||||
}
|
||||
LoadImmediate(A2, __ATOMIC_RELEASE);
|
||||
|
||||
switch (size) {
|
||||
case kEightBytes:
|
||||
rt.Call(kTsanAtomic64StoreRuntimeEntry, /*argument_count=*/3);
|
||||
break;
|
||||
case kFourBytes:
|
||||
case kUnsignedFourBytes:
|
||||
rt.Call(kTsanAtomic32StoreRuntimeEntry, /*argument_count=*/3);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::LoadAcquire(Register dst,
|
||||
@@ -3100,6 +3175,11 @@ void Assembler::LoadAcquire(Register dst,
|
||||
OperandSize size) {
|
||||
ASSERT(dst != address.base());
|
||||
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
TsanLoadAcquire(dst, address, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Supports(RV_Zalasr)) {
|
||||
Address addr = PrepareAtomicOffset(address.base(), address.offset());
|
||||
switch (size) {
|
||||
@@ -3124,20 +3204,16 @@ void Assembler::LoadAcquire(Register dst,
|
||||
Load(dst, address, size);
|
||||
fence(HartEffects::kRead, HartEffects::kMemory);
|
||||
}
|
||||
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
if (address.offset() == 0) {
|
||||
TsanLoadAcquire(address.base());
|
||||
} else {
|
||||
AddImmediate(TMP2, address.base(), address.offset());
|
||||
TsanLoadAcquire(TMP2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::StoreRelease(Register src,
|
||||
const Address& address,
|
||||
OperandSize size) {
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
TsanStoreRelease(src, address, size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Supports(RV_Zalasr)) {
|
||||
Address addr = PrepareAtomicOffset(address.base(), address.offset());
|
||||
switch (size) {
|
||||
@@ -4781,13 +4857,8 @@ void LeafRuntimeScope::Call(const RuntimeEntry& entry,
|
||||
|
||||
LeafRuntimeScope::~LeafRuntimeScope() {
|
||||
if (preserve_registers_) {
|
||||
const intptr_t kSavedRegistersSize =
|
||||
kRuntimeCallSavedRegisters.CpuRegisterCount() * target::kWordSize +
|
||||
kRuntimeCallSavedRegisters.FpuRegisterCount() * kFpuRegisterSize +
|
||||
4 * target::kWordSize;
|
||||
|
||||
__ subi(SP, FP, kSavedRegistersSize);
|
||||
|
||||
__ subi(SP, FP,
|
||||
kRuntimeCallSavedRegisters.SpillSize() + 4 * target::kWordSize);
|
||||
__ PopRegisters(kRuntimeCallSavedRegisters);
|
||||
}
|
||||
|
||||
|
||||
@@ -1007,8 +1007,8 @@ class Assembler : public MicroAssembler {
|
||||
StoreToOffset(src, base, offset, kWordBytes);
|
||||
}
|
||||
|
||||
void TsanLoadAcquire(Register addr);
|
||||
void TsanStoreRelease(Register addr);
|
||||
void TsanLoadAcquire(Register dst, const Address& address, OperandSize size);
|
||||
void TsanStoreRelease(Register src, const Address& address, OperandSize size);
|
||||
|
||||
void LoadAcquire(Register dst,
|
||||
const Address& address,
|
||||
|
||||
@@ -2106,15 +2106,7 @@ LeafRuntimeScope::~LeafRuntimeScope() {
|
||||
// RSP might have been modified to reserve space for arguments
|
||||
// and ensure proper alignment of the stack frame.
|
||||
// We need to restore it before restoring registers.
|
||||
const intptr_t kPushedCpuRegistersCount =
|
||||
RegisterSet::RegisterCount(CallingConventions::kVolatileCpuRegisters);
|
||||
const intptr_t kPushedXmmRegistersCount =
|
||||
RegisterSet::RegisterCount(CallingConventions::kVolatileXmmRegisters);
|
||||
const intptr_t kPushedRegistersSize =
|
||||
kPushedCpuRegistersCount * target::kWordSize +
|
||||
kPushedXmmRegistersCount * kFpuRegisterSize;
|
||||
|
||||
__ leaq(RSP, Address(RBP, -kPushedRegistersSize));
|
||||
__ leaq(RSP, Address(RBP, -kVolatileRegisterSet.SpillSize()));
|
||||
|
||||
// TODO(vegorov): avoid saving FpuTMP, it is used only as scratch.
|
||||
__ PopRegisters(kVolatileRegisterSet);
|
||||
@@ -2128,16 +2120,80 @@ LeafRuntimeScope::~LeafRuntimeScope() {
|
||||
__ LeaveFrame();
|
||||
}
|
||||
|
||||
void Assembler::TsanLoadAcquire(Address addr) {
|
||||
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
|
||||
void Assembler::TsanLoadAcquire(Register dst, Address addr, OperandSize size) {
|
||||
ASSERT(addr.base() != RSP);
|
||||
ASSERT(addr.base() != RBP);
|
||||
ASSERT(dst != RSP);
|
||||
ASSERT(dst != RBP);
|
||||
|
||||
RegisterSet registers(CallingConventions::kVolatileCpuRegisters & ~(1 << dst),
|
||||
CallingConventions::kVolatileXmmRegisters);
|
||||
|
||||
EnterFrame(0);
|
||||
PushRegisters(registers);
|
||||
ReserveAlignedFrameSpace(0);
|
||||
|
||||
leaq(CallingConventions::kArg1Reg, addr);
|
||||
rt.Call(kTsanLoadAcquireRuntimeEntry, /*argument_count=*/1);
|
||||
LoadImmediate(CallingConventions::kArg2Reg, __ATOMIC_ACQUIRE);
|
||||
|
||||
switch (size) {
|
||||
case kEightBytes:
|
||||
movq(RAX, compiler::Address(
|
||||
THR, kTsanAtomic64LoadRuntimeEntry.OffsetFromThread()));
|
||||
break;
|
||||
case kUnsignedFourBytes:
|
||||
movq(RAX, compiler::Address(
|
||||
THR, kTsanAtomic32LoadRuntimeEntry.OffsetFromThread()));
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
movq(compiler::Assembler::VMTagAddress(), RAX);
|
||||
CallCFunction(RAX);
|
||||
movq(compiler::Assembler::VMTagAddress(),
|
||||
compiler::Immediate(VMTag::kDartTagId));
|
||||
|
||||
MoveRegister(dst, RAX);
|
||||
|
||||
// RSP might have been modified to reserve space for arguments
|
||||
// and ensure proper alignment of the stack frame.
|
||||
// We need to restore it before restoring registers.
|
||||
leaq(RSP, Address(RBP, -registers.SpillSize()));
|
||||
|
||||
PopRegisters(registers);
|
||||
LeaveFrame();
|
||||
}
|
||||
|
||||
void Assembler::TsanStoreRelease(Address addr) {
|
||||
void Assembler::TsanStoreRelease(Register src, Address addr, OperandSize size) {
|
||||
ASSERT(addr.base() != RSP);
|
||||
ASSERT(addr.base() != RBP);
|
||||
ASSERT(src != RSP);
|
||||
ASSERT(src != RBP);
|
||||
|
||||
LeafRuntimeScope rt(this, /*frame_size=*/0, /*preserve_registers=*/true);
|
||||
leaq(CallingConventions::kArg1Reg, addr);
|
||||
rt.Call(kTsanStoreReleaseRuntimeEntry, /*argument_count=*/1);
|
||||
|
||||
if (CallingConventions::kArg1Reg == src) {
|
||||
MoveRegister(CallingConventions::kArg2Reg, src);
|
||||
leaq(CallingConventions::kArg1Reg, addr);
|
||||
} else {
|
||||
leaq(CallingConventions::kArg1Reg, addr);
|
||||
MoveRegister(CallingConventions::kArg2Reg, src);
|
||||
}
|
||||
LoadImmediate(CallingConventions::kArg3Reg, __ATOMIC_RELEASE);
|
||||
|
||||
switch (size) {
|
||||
case kEightBytes:
|
||||
rt.Call(kTsanAtomic64StoreRuntimeEntry, /*argument_count=*/3);
|
||||
break;
|
||||
case kFourBytes:
|
||||
case kUnsignedFourBytes:
|
||||
rt.Call(kTsanAtomic32StoreRuntimeEntry, /*argument_count=*/3);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::RestoreCodePointer() {
|
||||
|
||||
@@ -1159,37 +1159,35 @@ class Assembler : public AssemblerBase {
|
||||
}
|
||||
}
|
||||
|
||||
void TsanLoadAcquire(Address addr);
|
||||
void TsanStoreRelease(Address addr);
|
||||
void TsanLoadAcquire(Register dst, Address addr, OperandSize size);
|
||||
void TsanStoreRelease(Register src, Address addr, OperandSize size);
|
||||
|
||||
void LoadAcquire(Register dst,
|
||||
const Address& address,
|
||||
OperandSize size = kEightBytes) override {
|
||||
// On intel loads have load-acquire behavior (i.e. loads are not re-ordered
|
||||
// with other loads).
|
||||
Load(dst, address, size);
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
TsanLoadAcquire(address);
|
||||
TsanLoadAcquire(dst, address, size);
|
||||
} else {
|
||||
// On intel loads have load-acquire behavior (i.e. loads are not
|
||||
// re-ordered with other loads).
|
||||
Load(dst, address, size);
|
||||
}
|
||||
}
|
||||
#if defined(DART_COMPRESSED_POINTERS)
|
||||
void LoadAcquireCompressed(Register dst, const Address& address) override {
|
||||
// On intel loads have load-acquire behavior (i.e. loads are not re-ordered
|
||||
// with other loads).
|
||||
LoadCompressed(dst, address);
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
TsanLoadAcquire(address);
|
||||
}
|
||||
LoadAcquire(dst, address, kUnsignedFourBytes);
|
||||
addq(dst, Address(THR, target::Thread::heap_base_offset()));
|
||||
}
|
||||
#endif
|
||||
void StoreRelease(Register src,
|
||||
const Address& address,
|
||||
OperandSize size = kWordBytes) override {
|
||||
// On intel stores have store-release behavior (i.e. stores are not
|
||||
// re-ordered with other stores).
|
||||
Store(src, address, size);
|
||||
if (FLAG_target_thread_sanitizer) {
|
||||
TsanStoreRelease(address);
|
||||
TsanStoreRelease(src, address, size);
|
||||
} else {
|
||||
// On intel stores have store-release behavior (i.e. stores are not
|
||||
// re-ordered with other stores).
|
||||
Store(src, address, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6236,65 +6236,9 @@ ASSEMBLER_TEST_GENERATE(StoreReleaseLoadAcquire, assembler) {
|
||||
__ pushq(RCX);
|
||||
__ xorq(RCX, RCX);
|
||||
__ pushq(RCX);
|
||||
|
||||
for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) {
|
||||
XmmRegister xmm_reg = static_cast<XmmRegister>(i);
|
||||
if ((CallingConventions::kVolatileXmmRegisters & (1 << xmm_reg)) != 0) {
|
||||
__ movq(RCX, Immediate(bit_cast<int32_t, float>(12.34f + i)));
|
||||
__ movd(xmm_reg, RCX);
|
||||
}
|
||||
}
|
||||
|
||||
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
|
||||
Register reg = static_cast<Register>(i);
|
||||
if (reg == CallingConventions::kArg3Reg) {
|
||||
continue;
|
||||
}
|
||||
if ((CallingConventions::kVolatileCpuRegisters & (1 << reg)) != 0) {
|
||||
__ movq(reg, Immediate(0xAABBCCDD + i));
|
||||
}
|
||||
}
|
||||
__ StoreReleaseToOffset(CallingConventions::kArg3Reg, RSP, 0);
|
||||
|
||||
__ pushq(TMP);
|
||||
|
||||
for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) {
|
||||
Register reg = static_cast<Register>(i);
|
||||
if (reg == CallingConventions::kArg3Reg) {
|
||||
continue;
|
||||
}
|
||||
if ((CallingConventions::kVolatileCpuRegisters & (1 << reg)) != 0) {
|
||||
Label ok;
|
||||
if (reg == TMP) {
|
||||
__ popq(TMP);
|
||||
// Use kArg3Reg to validate TMP because TMP is
|
||||
// needed for 64-bit cmpq below.
|
||||
__ pushq(CallingConventions::kArg3Reg);
|
||||
__ movq(CallingConventions::kArg3Reg, TMP);
|
||||
reg = CallingConventions::kArg3Reg;
|
||||
}
|
||||
__ cmpq(reg, Immediate(0xAABBCCDD + i));
|
||||
__ j(EQUAL, &ok);
|
||||
__ int3();
|
||||
__ Bind(&ok);
|
||||
if (reg == CallingConventions::kArg3Reg) {
|
||||
__ popq(CallingConventions::kArg3Reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (intptr_t i = 0; i < kNumberOfXmmRegisters; ++i) {
|
||||
XmmRegister xmm_reg = static_cast<XmmRegister>(i);
|
||||
if ((CallingConventions::kVolatileXmmRegisters & (1 << xmm_reg)) != 0) {
|
||||
Label ok;
|
||||
__ movq(RCX, xmm_reg);
|
||||
__ cmpq(RCX, Immediate(bit_cast<int32_t, float>(12.34f + i)));
|
||||
__ j(EQUAL, &ok);
|
||||
__ int3();
|
||||
__ Bind(&ok);
|
||||
}
|
||||
}
|
||||
__ LoadAcquireFromOffset(CallingConventions::kReturnReg, RSP, 0);
|
||||
__ movq(RCX, RSP);
|
||||
__ StoreReleaseToOffset(CallingConventions::kArg3Reg, RCX, 0);
|
||||
__ LoadAcquireFromOffset(CallingConventions::kReturnReg, RCX, 0);
|
||||
__ popq(RCX);
|
||||
__ popq(RCX);
|
||||
__ popq(THR);
|
||||
@@ -6315,8 +6259,9 @@ ASSEMBLER_TEST_GENERATE(StoreReleaseLoadAcquire1024, assembler) {
|
||||
__ xorq(RCX, RCX);
|
||||
__ pushq(RCX);
|
||||
__ subq(RSP, Immediate(1024));
|
||||
__ StoreReleaseToOffset(CallingConventions::kArg3Reg, RSP, 1024);
|
||||
__ LoadAcquireFromOffset(CallingConventions::kReturnReg, RSP, 1024);
|
||||
__ movq(RCX, RSP);
|
||||
__ StoreReleaseToOffset(CallingConventions::kArg3Reg, RCX, 1024);
|
||||
__ LoadAcquireFromOffset(CallingConventions::kReturnReg, RCX, 1024);
|
||||
__ addq(RSP, Immediate(1024));
|
||||
__ popq(RCX);
|
||||
__ popq(RCX);
|
||||
@@ -6335,8 +6280,9 @@ ASSEMBLER_TEST_RUN(StoreReleaseLoadAcquire1024, test) {
|
||||
"xorq rcx,rcx\n"
|
||||
"push rcx\n"
|
||||
"subq rsp,0x400\n"
|
||||
"movq [rsp+0x400],rdx\n"
|
||||
"movq rax,[rsp+0x400]\n"
|
||||
"movq rcx,rsp\n"
|
||||
"movq [rcx+0x400],rdx\n"
|
||||
"movq rax,[rcx+0x400]\n"
|
||||
"addq rsp,0x400\n"
|
||||
"pop rcx\n"
|
||||
"pop rcx\n"
|
||||
|
||||
@@ -6095,9 +6095,8 @@ class ShiftInt64OpSlowPath : public ThrowErrorSlowPathCode {
|
||||
// The unboxed int64 argument is passed through a dedicated slot in Thread.
|
||||
// TODO(dartbug.com/33549): Clean this up when unboxed values
|
||||
// could be passed as arguments.
|
||||
__ sx(right,
|
||||
compiler::Address(
|
||||
THR, compiler::target::Thread::unboxed_runtime_arg_offset()));
|
||||
__ StoreToOffset(right, THR,
|
||||
compiler::target::Thread::unboxed_runtime_arg_offset());
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
@@ -820,6 +820,10 @@ class RegisterSet : public ValueObject {
|
||||
|
||||
intptr_t CpuRegisterCount() const { return RegisterCount(cpu_registers()); }
|
||||
intptr_t FpuRegisterCount() const { return RegisterCount(fpu_registers()); }
|
||||
intptr_t SpillSize() const {
|
||||
return CpuRegisterCount() * compiler::target::kWordSize +
|
||||
FpuRegisterCount() * kFpuRegisterSize;
|
||||
}
|
||||
|
||||
bool IsEmpty() const {
|
||||
return CpuRegisterCount() == 0 && FpuRegisterCount() == 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4872,10 +4872,20 @@ extern "C" void __msan_unpoison_param(size_t) {
|
||||
#endif
|
||||
|
||||
#if !defined(USING_THREAD_SANITIZER)
|
||||
extern "C" void __tsan_acquire(void* addr) {
|
||||
extern "C" uint32_t __tsan_atomic32_load(uint32_t* addr, int order) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
extern "C" void __tsan_release(void* addr) {
|
||||
extern "C" void __tsan_atomic32_store(uint32_t* addr,
|
||||
uint32_t value,
|
||||
int order) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
extern "C" uint64_t __tsan_atomic64_load(uint64_t* addr, int order) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
extern "C" void __tsan_atomic64_store(uint64_t* addr,
|
||||
uint64_t value,
|
||||
int order) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
@@ -4885,7 +4895,9 @@ extern "C" void __tsan_release(void* addr) {
|
||||
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(MsanUnpoison, 2, __msan_unpoison);
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(MsanUnpoisonParam, 1, __msan_unpoison_param);
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(TsanLoadAcquire, 1, __tsan_acquire);
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(TsanStoreRelease, 1, __tsan_release);
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(TsanAtomic32Load, 2, __tsan_atomic32_load);
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(TsanAtomic32Store, 3, __tsan_atomic32_store);
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(TsanAtomic64Load, 2, __tsan_atomic64_load);
|
||||
DEFINE_LEAF_RUNTIME_ENTRY(TsanAtomic64Store, 3, __tsan_atomic64_store);
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -127,8 +127,10 @@ namespace dart {
|
||||
V(void, PropagateError, Dart_Handle) \
|
||||
V(void, MsanUnpoison, void*, size_t) \
|
||||
V(void, MsanUnpoisonParam, size_t) \
|
||||
V(void, TsanLoadAcquire, void*) \
|
||||
V(void, TsanStoreRelease, void*) \
|
||||
V(uint32_t, TsanAtomic32Load, void*, int) \
|
||||
V(void, TsanAtomic32Store, void*, uint32_t, int) \
|
||||
V(uint64_t, TsanAtomic64Load, void*, int) \
|
||||
V(void, TsanAtomic64Store, void*, uint64_t, int) \
|
||||
V(bool, TryDoubleAsInteger, Thread*) \
|
||||
V(void*, MemoryMove, void*, const void*, size_t)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user