tsan: use dynamic shadow stack for Go


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@160288 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index 6406cdc..ca8f0ae 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -28,9 +28,7 @@
 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
+#ifndef TSAN_GO
 const int kShadowStackSize = 1024;
 #endif
 
diff --git a/lib/tsan/rtl/tsan_mman.h b/lib/tsan/rtl/tsan_mman.h
index b338a9c..53f147e 100644
--- a/lib/tsan/rtl/tsan_mman.h
+++ b/lib/tsan/rtl/tsan_mman.h
@@ -36,6 +36,7 @@
   MBlockScopedBuf,
   MBlockString,
   MBlockStackTrace,
+  MBlockShadowStack,
   MBlockSync,
   MBlockClock,
   MBlockThreadContex,
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index f27a541..81c3f72 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -451,14 +451,28 @@
 void FuncEntry(ThreadState *thr, uptr pc) {
   DCHECK_EQ(thr->in_rtl, 0);
   StatInc(thr, StatFuncEnter);
-  DPrintf2("#%d: tsan::FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
+  DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeFuncEnter, pc);
 
   // Shadow stack maintenance can be replaced with
   // stack unwinding during trace switch (which presumably must be faster).
   DCHECK_GE(thr->shadow_stack_pos, &thr->shadow_stack[0]);
+#ifndef TSAN_GO
   DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+#else
+  if (thr->shadow_stack_pos == thr->shadow_stack_end) {
+    const int sz = thr->shadow_stack_end - thr->shadow_stack;
+    const int newsz = 2 * sz;
+    uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack,
+        newsz * sizeof(uptr));
+    internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr));
+    internal_free(thr->shadow_stack);
+    thr->shadow_stack = newstack;
+    thr->shadow_stack_pos = newstack + sz;
+    thr->shadow_stack_end = newstack + newsz;
+  }
+#endif
   thr->shadow_stack_pos[0] = pc;
   thr->shadow_stack_pos++;
 }
@@ -466,12 +480,14 @@
 void FuncExit(ThreadState *thr) {
   DCHECK_EQ(thr->in_rtl, 0);
   StatInc(thr, StatFuncExit);
-  DPrintf2("#%d: tsan::FuncExit\n", (int)thr->fast_state.tid());
+  DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
   thr->fast_state.IncrementEpoch();
   TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeFuncExit, 0);
 
   DCHECK_GT(thr->shadow_stack_pos, &thr->shadow_stack[0]);
+#ifndef TSAN_GO
   DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+#endif
   thr->shadow_stack_pos--;
 }
 
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 0d717d3..5cb95da 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -228,7 +228,14 @@
   u64 *racy_shadow_addr;
   u64 racy_state[2];
   Trace trace;
+#ifndef TSAN_GO
+  // C/C++ uses embed shadow stack of fixed size.
   uptr shadow_stack[kShadowStackSize];
+#else
+  // Go uses satellite shadow stack with dynamic size.
+  uptr *shadow_stack;
+  uptr *shadow_stack_end;
+#endif
   ThreadClock clock;
   u64 stat[StatCnt];
   const int tid;
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index 81242a7..6756bd3 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -173,6 +173,14 @@
   tctx->epoch1 = (u64)-1;
   new(thr) ThreadState(CTX(), tid, tctx->epoch0, stk_addr, stk_size,
                        tls_addr, tls_size);
+#ifdef TSAN_GO
+  // Setup dynamic shadow stack.
+  const int kInitStackSize = 8;
+  thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
+      kInitStackSize * sizeof(uptr));
+  thr->shadow_stack_pos = thr->shadow_stack;
+  thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
+#endif
   tctx->thr = thr;
   thr->fast_synch_epoch = tctx->epoch0;
   thr->clock.set(tid, tctx->epoch0);
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index ebe7df4..2014121 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -174,7 +174,7 @@
 
 void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
   Reset();
-  n_ = thr->shadow_stack_pos - &thr->shadow_stack[0];
+  n_ = thr->shadow_stack_pos - thr->shadow_stack;
   if (n_ + !!toppc == 0)
     return;
   if (c_) {
diff --git a/lib/tsan/rtl/tsan_trace.h b/lib/tsan/rtl/tsan_trace.h
index 1109d1d..a585374 100644
--- a/lib/tsan/rtl/tsan_trace.h
+++ b/lib/tsan/rtl/tsan_trace.h
@@ -42,10 +42,16 @@
 struct TraceHeader {
   StackTrace stack0;  // Start stack for the trace.
   u64        epoch0;  // Start epoch for the trace.
+#ifndef TSAN_GO
   uptr       stack0buf[kShadowStackSize];
+#endif
 
   TraceHeader()
+#ifndef TSAN_GO
       : stack0(stack0buf, kShadowStackSize)
+#else
+      : stack0()
+#endif
       , epoch0() {
   }
 };