[vm, compiler] Don't do safepoint transitions in generated code under TSAN.
Go to the runtime so TSAN sees the instrumented access to Thread::safepoint_state_, avoiding false data race reports. TEST=tsan Bug: https://github.com/dart-lang/sdk/issues/52024 Change-Id: Ic686bac2221d8ac6b9865ce9c82a4c36711037a7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/295740 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
Commit Queue
parent
39fc15a0b4
commit
c4795a7550
@@ -17,8 +17,10 @@
|
||||
#define NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
|
||||
extern "C" void __tsan_acquire(void* addr);
|
||||
extern "C" void __tsan_release(void* addr);
|
||||
constexpr bool kUsingThreadSanitizer = true;
|
||||
#else
|
||||
#define NO_SANITIZE_THREAD
|
||||
constexpr bool kUsingThreadSanitizer = false;
|
||||
#endif
|
||||
|
||||
#if defined(USING_THREAD_SANITIZER)
|
||||
|
||||
@@ -1643,12 +1643,14 @@ void Assembler::LeaveDartFrame() {
|
||||
void Assembler::EnterFullSafepoint(Register state) {
|
||||
// We generate the same number of instructions whether or not the slow-path is
|
||||
// forced. This simplifies GenerateJitCallbackTrampolines.
|
||||
// For TSAN, we always go to the runtime so TSAN is aware of the release
|
||||
// semantics of entering the safepoint.
|
||||
|
||||
Register addr = TMP2;
|
||||
ASSERT(addr != state);
|
||||
|
||||
Label slow_path, done, retry;
|
||||
if (FLAG_use_slow_path) {
|
||||
if (FLAG_use_slow_path || kUsingThreadSanitizer) {
|
||||
b(&slow_path);
|
||||
}
|
||||
|
||||
@@ -1663,7 +1665,7 @@ void Assembler::EnterFullSafepoint(Register state) {
|
||||
stxr(TMP, state, addr);
|
||||
cbz(&done, TMP); // 0 means stxr was successful.
|
||||
|
||||
if (!FLAG_use_slow_path) {
|
||||
if (!FLAG_use_slow_path && !kUsingThreadSanitizer) {
|
||||
b(&retry);
|
||||
}
|
||||
|
||||
@@ -1701,11 +1703,13 @@ void Assembler::ExitFullSafepoint(Register state,
|
||||
bool ignore_unwind_in_progress) {
|
||||
// We generate the same number of instructions whether or not the slow-path is
|
||||
// forced, for consistency with EnterFullSafepoint.
|
||||
// For TSAN, we always go to the runtime so TSAN is aware of the acquire
|
||||
// semantics of leaving the safepoint.
|
||||
Register addr = TMP2;
|
||||
ASSERT(addr != state);
|
||||
|
||||
Label slow_path, done, retry;
|
||||
if (FLAG_use_slow_path) {
|
||||
if (FLAG_use_slow_path || kUsingThreadSanitizer) {
|
||||
b(&slow_path);
|
||||
}
|
||||
|
||||
@@ -1720,7 +1724,7 @@ void Assembler::ExitFullSafepoint(Register state,
|
||||
stxr(TMP, state, addr);
|
||||
cbz(&done, TMP); // 0 means stxr was successful.
|
||||
|
||||
if (!FLAG_use_slow_path) {
|
||||
if (!FLAG_use_slow_path && !kUsingThreadSanitizer) {
|
||||
b(&retry);
|
||||
}
|
||||
|
||||
|
||||
@@ -3863,12 +3863,14 @@ void Assembler::TransitionNativeToGenerated(Register state,
|
||||
void Assembler::EnterFullSafepoint(Register state) {
|
||||
// We generate the same number of instructions whether or not the slow-path is
|
||||
// forced. This simplifies GenerateJitCallbackTrampolines.
|
||||
// For TSAN, we always go to the runtime so TSAN is aware of the release
|
||||
// semantics of entering the safepoint.
|
||||
|
||||
Register addr = RA;
|
||||
ASSERT(addr != state);
|
||||
|
||||
Label slow_path, done, retry;
|
||||
if (FLAG_use_slow_path) {
|
||||
if (FLAG_use_slow_path || kUsingThreadSanitizer) {
|
||||
j(&slow_path, Assembler::kNearJump);
|
||||
}
|
||||
|
||||
@@ -3882,7 +3884,7 @@ void Assembler::EnterFullSafepoint(Register state) {
|
||||
sc(state, state, Address(addr, 0));
|
||||
beqz(state, &done, Assembler::kNearJump); // 0 means sc was successful.
|
||||
|
||||
if (!FLAG_use_slow_path) {
|
||||
if (!FLAG_use_slow_path && !kUsingThreadSanitizer) {
|
||||
j(&retry, Assembler::kNearJump);
|
||||
}
|
||||
|
||||
@@ -3898,11 +3900,13 @@ void Assembler::ExitFullSafepoint(Register state,
|
||||
bool ignore_unwind_in_progress) {
|
||||
// We generate the same number of instructions whether or not the slow-path is
|
||||
// forced, for consistency with EnterFullSafepoint.
|
||||
// For TSAN, we always go to the runtime so TSAN is aware of the acquire
|
||||
// semantics of leaving the safepoint.
|
||||
Register addr = RA;
|
||||
ASSERT(addr != state);
|
||||
|
||||
Label slow_path, done, retry;
|
||||
if (FLAG_use_slow_path) {
|
||||
if (FLAG_use_slow_path || kUsingThreadSanitizer) {
|
||||
j(&slow_path, Assembler::kNearJump);
|
||||
}
|
||||
|
||||
@@ -3916,7 +3920,7 @@ void Assembler::ExitFullSafepoint(Register state,
|
||||
sc(state, state, Address(addr, 0));
|
||||
beqz(state, &done, Assembler::kNearJump); // 0 means sc was successful.
|
||||
|
||||
if (!FLAG_use_slow_path) {
|
||||
if (!FLAG_use_slow_path && !kUsingThreadSanitizer) {
|
||||
j(&retry, Assembler::kNearJump);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,8 +129,10 @@ void Assembler::setcc(Condition condition, ByteRegister dst) {
|
||||
void Assembler::EnterFullSafepoint() {
|
||||
// We generate the same number of instructions whether or not the slow-path is
|
||||
// forced, to simplify GenerateJitCallbackTrampolines.
|
||||
// For TSAN, we always go to the runtime so TSAN is aware of the release
|
||||
// semantics of entering the safepoint.
|
||||
Label done, slow_path;
|
||||
if (FLAG_use_slow_path) {
|
||||
if (FLAG_use_slow_path || kUsingThreadSanitizer) {
|
||||
jmp(&slow_path);
|
||||
}
|
||||
|
||||
@@ -144,7 +146,7 @@ void Assembler::EnterFullSafepoint() {
|
||||
popq(RAX);
|
||||
cmpq(TMP, Immediate(target::Thread::full_safepoint_state_unacquired()));
|
||||
|
||||
if (!FLAG_use_slow_path) {
|
||||
if (!FLAG_use_slow_path && !kUsingThreadSanitizer) {
|
||||
j(EQUAL, &done);
|
||||
}
|
||||
|
||||
@@ -184,8 +186,10 @@ void Assembler::TransitionGeneratedToNative(Register destination_address,
|
||||
void Assembler::ExitFullSafepoint(bool ignore_unwind_in_progress) {
|
||||
// We generate the same number of instructions whether or not the slow-path is
|
||||
// forced, for consistency with EnterFullSafepoint.
|
||||
// For TSAN, we always go to the runtime so TSAN is aware of the acquire
|
||||
// semantics of leaving the safepoint.
|
||||
Label done, slow_path;
|
||||
if (FLAG_use_slow_path) {
|
||||
if (FLAG_use_slow_path || kUsingThreadSanitizer) {
|
||||
jmp(&slow_path);
|
||||
}
|
||||
|
||||
@@ -201,7 +205,7 @@ void Assembler::ExitFullSafepoint(bool ignore_unwind_in_progress) {
|
||||
popq(RAX);
|
||||
cmpq(TMP, Immediate(target::Thread::full_safepoint_state_acquired()));
|
||||
|
||||
if (!FLAG_use_slow_path) {
|
||||
if (!FLAG_use_slow_path && !kUsingThreadSanitizer) {
|
||||
j(EQUAL, &done);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user