tsan: Go language support

llvm-svn: 159754
diff --git a/compiler-rt/lib/tsan/rtl/tsan_defs.h b/compiler-rt/lib/tsan/rtl/tsan_defs.h
index 3d9cd54..6406cdc 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_defs.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_defs.h
@@ -28,7 +28,11 @@
 const unsigned kMaxTid = 1 << kTidBits;
 const unsigned kMaxTidInClock = kMaxTid * 2;  // This includes msb 'freed' bit.
 const int kClkBits = 43;
+#ifdef TSAN_GO
+const int kShadowStackSize = 8 * 1024;
+#else
 const int kShadowStackSize = 1024;
+#endif
 
 #ifdef TSAN_SHADOW_COUNT
 # if TSAN_SHADOW_COUNT == 2 \
@@ -119,9 +123,7 @@
 
 struct MD5Hash {
   u64 hash[2];
-  bool operator==(const MD5Hash &other) const {
-    return hash[0] == other.hash[0] && hash[1] == other.hash[1];
-  }
+  bool operator==(const MD5Hash &other) const;
 };
 
 MD5Hash md5_hash(const void *data, uptr size);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_flags.cc b/compiler-rt/lib/tsan/rtl/tsan_flags.cc
index 1474450..f2987c4 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_flags.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_flags.cc
@@ -53,7 +53,6 @@
   f->running_on_valgrind = false;
   f->use_internal_symbolizer = false;
 
-
   // Let a frontend override.
   OverrideFlags(f);
 
diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
index 68eab5d..1a70f8f 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_mutex.cc
@@ -198,7 +198,7 @@
 }
 
 void Mutex::Lock() {
-#if TSAN_DEBUG
+#if TSAN_DEBUG && !TSAN_GO
   cur_thread()->deadlock_detector.Lock(type_);
 #endif
   uptr cmp = kUnlocked;
@@ -223,13 +223,13 @@
   uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
   (void)prev;
   DCHECK_NE(prev & kWriteLock, 0);
-#if TSAN_DEBUG
+#if TSAN_DEBUG && !TSAN_GO
   cur_thread()->deadlock_detector.Unlock(type_);
 #endif
 }
 
 void Mutex::ReadLock() {
-#if TSAN_DEBUG
+#if TSAN_DEBUG && !TSAN_GO
   cur_thread()->deadlock_detector.Lock(type_);
 #endif
   uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
@@ -251,7 +251,7 @@
   (void)prev;
   DCHECK_EQ(prev & kWriteLock, 0);
   DCHECK_GT(prev & ~kWriteLock, 0);
-#if TSAN_DEBUG
+#if TSAN_DEBUG && !TSAN_GO
   cur_thread()->deadlock_detector.Unlock(type_);
 #endif
 }
diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform.h b/compiler-rt/lib/tsan/rtl/tsan_platform.h
index b469437..1505145 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform.h
@@ -21,26 +21,30 @@
 #if __LP64__
 namespace __tsan {
 
+#if defined(TSAN_GO)
+static const uptr kLinuxAppMemBeg = 0x000000000000ULL;
+static const uptr kLinuxAppMemEnd = 0x00fcffffffffULL;
+static const uptr kLinuxShadowMsk = 0x100000000000ULL;
 // TSAN_COMPAT_SHADOW is intended for COMPAT virtual memory layout,
 // when memory addresses are of the 0x2axxxxxxxxxx form.
 // The option is enabled with 'setarch x86_64 -L'.
-#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
-
+#elif defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
 static const uptr kLinuxAppMemBeg = 0x2a0000000000ULL;
 static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
-
 #else
-
 static const uptr kLinuxAppMemBeg = 0x7ef000000000ULL;
 static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
-
 #endif
 
 static const uptr kLinuxAppMemMsk = 0x7c0000000000ULL;
 
 // This has to be a macro to allow constant initialization of constants below.
+#ifndef TSAN_GO
 #define MemToShadow(addr) \
     (((addr) & ~(kLinuxAppMemMsk | (kShadowCell - 1))) * kShadowCnt)
+#else
+#define MemToShadow(addr) (((addr) * kShadowCnt) | kLinuxShadowMsk)
+#endif
 
 static const uptr kLinuxShadowBeg = MemToShadow(kLinuxAppMemBeg);
 static const uptr kLinuxShadowEnd =
@@ -56,7 +60,9 @@
 
 static inline uptr ShadowToMem(uptr shadow) {
   CHECK(IsShadowMem(shadow));
-#if defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
+#ifdef TSAN_GO
+  return (shadow & ~kLinuxShadowMsk) / kShadowCnt;
+#elif defined(TSAN_COMPAT_SHADOW) && TSAN_COMPAT_SHADOW
   // COMPAT mapping is not quite one-to-one.
   return (shadow / kShadowCnt) | 0x280000000000ULL;
 #else
diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
index e2fe3e8..269f9ee 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc
@@ -51,8 +51,7 @@
 
 namespace __tsan {
 
-static uptr g_tls_size;
-
+#ifndef TSAN_GO
 ScopedInRtl::ScopedInRtl()
     : thr_(cur_thread()) {
   in_rtl_ = thr_->in_rtl;
@@ -65,6 +64,13 @@
   errno = errno_;
   CHECK_EQ(in_rtl_, thr_->in_rtl);
 }
+#else
+ScopedInRtl::ScopedInRtl() {
+}
+
+ScopedInRtl::~ScopedInRtl() {
+}
+#endif
 
 uptr GetShadowMemoryConsumption() {
   return 0;
@@ -76,6 +82,7 @@
           MADV_DONTNEED);
 }
 
+#ifndef TSAN_GO
 static void ProtectRange(uptr beg, uptr end) {
   ScopedInRtl in_rtl;
   CHECK_LE(beg, end);
@@ -87,12 +94,9 @@
     Die();
   }
 }
+#endif
 
 void InitializeShadowMemory() {
-  const uptr kClosedLowBeg  = 0x200000;
-  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
-  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
-  const uptr kClosedMidEnd = kLinuxAppMemBeg - 1;
   uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
     kLinuxShadowEnd - kLinuxShadowBeg);
   if (shadow != kLinuxShadowBeg) {
@@ -101,21 +105,32 @@
                "to link with -pie.\n");
     Die();
   }
+#ifndef TSAN_GO
+  const uptr kClosedLowBeg  = 0x200000;
+  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
+  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
+  const uptr kClosedMidEnd = kLinuxAppMemBeg - 1;
   ProtectRange(kClosedLowBeg, kClosedLowEnd);
   ProtectRange(kClosedMidBeg, kClosedMidEnd);
+#endif
+#ifndef TSAN_GO
   DPrintf("kClosedLow   %zx-%zx (%zuGB)\n",
       kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
+#endif
   DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
       kLinuxShadowBeg, kLinuxShadowEnd,
       (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
+#ifndef TSAN_GO
   DPrintf("kClosedMid   %zx-%zx (%zuGB)\n",
       kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
+#endif
   DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
       kLinuxAppMemBeg, kLinuxAppMemEnd,
       (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
   DPrintf("stack        %zx\n", (uptr)&shadow);
 }
 
+#ifndef TSAN_GO
 static void CheckPIE() {
   // Ensure that the binary is indeed compiled with -pie.
   ProcessMaps proc_maps;
@@ -133,6 +148,8 @@
   }
 }
 
+static uptr g_tls_size;
+
 #ifdef __i386__
 # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
 #else
@@ -152,6 +169,7 @@
   get_tls(&tls_size, &tls_align);
   return tls_size;
 }
+#endif  // #ifndef TSAN_GO
 
 const char *InitializePlatform() {
   void *p = 0;
@@ -164,8 +182,10 @@
     setrlimit(RLIMIT_CORE, (rlimit*)&lim);
   }
 
+#ifndef TSAN_GO
   CheckPIE();
   g_tls_size = (uptr)InitTlsSize();
+#endif
   return getenv("TSAN_OPTIONS");
 }
 
@@ -174,11 +194,16 @@
 }
 
 uptr GetTlsSize() {
+#ifndef TSAN_GO
   return g_tls_size;
+#else
+  return 0;
+#endif
 }
 
 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
                           uptr *tls_addr, uptr *tls_size) {
+#ifndef TSAN_GO
   arch_prctl(ARCH_GET_FS, tls_addr);
   *tls_addr -= g_tls_size;
   *tls_size = g_tls_size;
@@ -197,6 +222,13 @@
       *tls_addr = *stk_addr + *stk_size;
     }
   }
+#else
+  *stk_addr = 0;
+  *stk_size = 0;
+  *tls_addr = 0;
+  *tls_size = 0;
+#endif
 }
 
+
 }  // namespace __tsan
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
index 822dfa1..f27a541 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc
@@ -31,7 +31,9 @@
 
 namespace __tsan {
 
+#ifndef TSAN_GO
 THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
+#endif
 static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
 
 static Context *ctx;
@@ -218,7 +220,7 @@
   return failed ? flags()->exitcode : 0;
 }
 
-static void TraceSwitch(ThreadState *thr) {
+void TraceSwitch(ThreadState *thr) {
   thr->nomalloc++;
   ScopedInRtl in_rtl;
   Lock l(&thr->trace.mtx);
@@ -229,6 +231,7 @@
   thr->nomalloc--;
 }
 
+#ifndef TSAN_GO
 extern "C" void __tsan_trace_switch() {
   TraceSwitch(cur_thread());
 }
@@ -236,6 +239,7 @@
 extern "C" void __tsan_report_race() {
   ReportRace(cur_thread());
 }
+#endif
 
 ALWAYS_INLINE
 static Shadow LoadShadow(u64 *p) {
@@ -259,7 +263,11 @@
   thr->racy_state[0] = cur.raw();
   thr->racy_state[1] = old.raw();
   thr->racy_shadow_addr = shadow_mem;
+#ifndef TSAN_GO
   HACKY_CALL(__tsan_report_race);
+#else
+  ReportRace(thr);
+#endif
 }
 
 static inline bool BothReads(Shadow s, int kAccessIsWrite) {
@@ -477,6 +485,10 @@
     thr->fast_state.ClearIgnoreBit();
 }
 
+bool MD5Hash::operator==(const MD5Hash &other) const {
+  return hash[0] == other.hash[0] && hash[1] == other.hash[1];
+}
+
 #if TSAN_DEBUG
 void build_consistency_debug() {}
 #else
@@ -501,5 +513,7 @@
 
 }  // namespace __tsan
 
+#ifndef TSAN_GO
 // Must be included in this file to make sure everything is inlined.
 #include "tsan_interface_inl.h"
+#endif
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 71ca5d4..0d717d3 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -254,11 +254,13 @@
 };
 
 Context *CTX();
-extern THREADLOCAL char cur_thread_placeholder[];
 
+#ifndef TSAN_GO
+extern THREADLOCAL char cur_thread_placeholder[];
 INLINE ThreadState *cur_thread() {
   return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
 }
+#endif
 
 enum ThreadStatus {
   ThreadStatusInvalid,   // Non-existent thread, data is invalid.
@@ -457,12 +459,19 @@
 #define HACKY_CALL(f) f()
 #endif
 
+void TraceSwitch(ThreadState *thr);
+
 extern "C" void __tsan_trace_switch();
 void ALWAYS_INLINE INLINE TraceAddEvent(ThreadState *thr, u64 epoch,
                                         EventType typ, uptr addr) {
   StatInc(thr, StatEvents);
-  if (UNLIKELY((epoch % kTracePartSize) == 0))
+  if (UNLIKELY((epoch % kTracePartSize) == 0)) {
+#ifndef TSAN_GO
     HACKY_CALL(__tsan_trace_switch);
+#else
+    TraceSwitch(thr);
+#endif
+  }
   Event *evp = &thr->trace.events[epoch % kTraceSize];
   Event ev = (u64)addr | ((u64)typ << 61);
   *evp = ev;
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
index 68a5c3e2..42cd523 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -142,18 +142,22 @@
   GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
 
   if (tid) {
-    MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size);
+    if (stk_addr && stk_size) {
+      MemoryResetRange(thr, /*pc=*/ 1, stk_addr, stk_size);
+    }
 
-    // Check that the thr object is in tls;
-    const uptr thr_beg = (uptr)thr;
-    const uptr thr_end = (uptr)thr + sizeof(*thr);
-    CHECK_GE(thr_beg, tls_addr);
-    CHECK_LE(thr_beg, tls_addr + tls_size);
-    CHECK_GE(thr_end, tls_addr);
-    CHECK_LE(thr_end, tls_addr + tls_size);
-    // Since the thr object is huge, skip it.
-    MemoryResetRange(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
-    MemoryResetRange(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end);
+    if (tls_addr && tls_size) {
+      // Check that the thr object is in tls;
+      const uptr thr_beg = (uptr)thr;
+      const uptr thr_end = (uptr)thr + sizeof(*thr);
+      CHECK_GE(thr_beg, tls_addr);
+      CHECK_LE(thr_beg, tls_addr + tls_size);
+      CHECK_GE(thr_end, tls_addr);
+      CHECK_LE(thr_end, tls_addr + tls_size);
+      // Since the thr object is huge, skip it.
+      MemoryResetRange(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
+      MemoryResetRange(thr, /*pc=*/ 2, thr_end, tls_addr + tls_size - thr_end);
+    }
   }
 
   Lock l(&CTX()->thread_mtx);