diff --git a/runtime/platform/thread_sanitizer.h b/runtime/platform/thread_sanitizer.h index b82fde933a8..0983dd0539d 100644 --- a/runtime/platform/thread_sanitizer.h +++ b/runtime/platform/thread_sanitizer.h @@ -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) diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc index 6195495a8c0..02cfd3b2307 100644 --- a/runtime/vm/compiler/assembler/assembler_arm64.cc +++ b/runtime/vm/compiler/assembler/assembler_arm64.cc @@ -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); } diff --git a/runtime/vm/compiler/assembler/assembler_riscv.cc b/runtime/vm/compiler/assembler/assembler_riscv.cc index 6c7ffa8fd70..ec963313761 100644 --- a/runtime/vm/compiler/assembler/assembler_riscv.cc +++ b/runtime/vm/compiler/assembler/assembler_riscv.cc @@ -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); } diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc index 7b34aa18a55..cb266962f8f 100644 --- a/runtime/vm/compiler/assembler/assembler_x64.cc +++ b/runtime/vm/compiler/assembler/assembler_x64.cc @@ -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); }