[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:
Ryan Macnak
2025-08-04 15:29:04 -07:00
committed by Commit Queue
parent 8b97e6c6a4
commit dc97aa7fb9
13 changed files with 551 additions and 405 deletions
+8 -2
View File
@@ -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,
+71 -15
View File
@@ -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() {
+14 -16
View File
@@ -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"
+2 -3
View File
@@ -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
}
};
+4
View File
@@ -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
+16 -4
View File
@@ -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
+4 -2
View File
@@ -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)