runtime: add GODEBUG gcshrinkstackoff, gcstackbarrieroff, and gcstoptheworld variables

While we're here, update the documentation and delete variables with no effect.

Change-Id: I4df0d266dff880df61b488ed547c2870205862f0
Reviewed-on: https://go-review.googlesource.com/10790
Reviewed-by: Austin Clements <austin@google.com>
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 476c3c5..3882229 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -21,8 +21,8 @@
 The runtime/debug package's SetGCPercent function allows changing this
 percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
 
-The GODEBUG variable controls debug output from the runtime. GODEBUG value is
-a comma-separated list of name=val pairs. Supported names are:
+The GODEBUG variable controls debugging variables within the runtime.
+It is a comma-separated list of name=val pairs setting these named variables:
 
 	allocfreetrace: setting allocfreetrace=1 causes every allocation to be
 	profiled and a stack trace printed on each object's allocation and free.
@@ -31,13 +31,34 @@
 	where each object is allocated on a unique page and addresses are
 	never recycled.
 
+	gccheckmark: setting gccheckmark=1 enables verification of the
+	garbage collector's concurrent mark phase by performing a
+	second mark pass while the world is stopped.  If the second
+	pass finds a reachable object that was not found by concurrent
+	mark, the garbage collector will panic.
+
+	gcpacertrace: setting gcpacertrace=1 causes the garbage collector to
+	print information about the internal state of the concurrent pacer.
+
+	gcshrinkstackoff: setting gcshrinkstackoff=1 disables moving goroutines
+	onto smaller stacks. In this mode, a goroutine's stack can only grow.
+
+	gcstackbarrieroff: setting gcstackbarrieroff=1 disables the use of stack barriers
+	that allow the garbage collector to avoid repeating a stack scan during the
+	mark termination phase.
+
+	gcstoptheworld: setting gcstoptheworld=1 disables concurrent garbage collection,
+	making every garbage collection a stop-the-world event. Setting gcstoptheworld=2
+	also disables concurrent sweeping after the garbage collection finishes.
+
 	gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard
 	error at each collection, summarizing the amount of memory collected and the
 	length of the pause. Setting gctrace=2 emits the same summary but also
 	repeats each collection.
 
-	gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
-	that it thinks are dead.
+	memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
+	When set to 0 memory profiling is disabled.  Refer to the description of
+	MemProfileRate for the default value.
 
 	invalidptr: defaults to invalidptr=1, causing the garbage collector and stack
 	copier to crash the program if an invalid pointer value (for example, 1)
@@ -45,9 +66,11 @@
 	This should only be used as a temporary workaround to diagnose buggy code.
 	The real fix is to not store integers in pointer-typed locations.
 
-	memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
-	When set to 0 memory profiling is disabled.  Refer to the description of
-	MemProfileRate for the default value.
+	sbrk: setting sbrk=1 replaces the memory allocator and garbage collector
+	with a trivial allocator that obtains memory from the operating system and
+	never reclaims any memory.
+
+	scavenge: scavenge=1 enables debugging mode of heap scavenger.
 
 	scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
 	detailed multiline info every X milliseconds, describing state of the scheduler,
@@ -56,14 +79,6 @@
 	schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
 	error every X milliseconds, summarizing the scheduler state.
 
-	scavenge: scavenge=1 enables debugging mode of heap scavenger.
-
-	gccheckmark: setting gccheckmark=1 enables verification of the
-	garbage collector's concurrent mark phase by performing a
-	second mark pass while the world is stopped.  If the second
-	pass finds a reachable object that was not found by concurrent
-	mark, the garbage collector will panic.
-
 The GOMAXPROCS variable limits the number of operating system threads that
 can execute user-level Go code simultaneously. There is no limit to the number of threads
 that can be blocked in system calls on behalf of Go code; those do not count against
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 53d6797..b7b9ac1 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -740,6 +740,12 @@
 	releasem(mp)
 	mp = nil
 
+	if debug.gcstoptheworld == 1 {
+		mode = gcForceMode
+	} else if debug.gcstoptheworld == 2 {
+		mode = gcForceBlockMode
+	}
+
 	if mode != gcBackgroundMode {
 		// special synchronous cases
 		gc(mode)
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index dead22a..f5fa52d 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -327,6 +327,10 @@
 		barrierOffset = firstStackBarrierOffset
 		nextBarrier = sp + barrierOffset
 
+		if debug.gcstackbarrieroff > 0 {
+			nextBarrier = ^uintptr(0)
+		}
+
 		if gp.stkbarPos != 0 || len(gp.stkbar) != 0 {
 			// If this happens, it's probably because we
 			// scanned a stack twice in the same phase.
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
index ea38830..e483178 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -306,33 +306,37 @@
 // existing int var for that value, which may
 // already have an initial value.
 var debug struct {
-	allocfreetrace int32
-	efence         int32
-	gcdead         int32
-	gctrace        int32
-	invalidptr     int32
-	scavenge       int32
-	scheddetail    int32
-	schedtrace     int32
-	wbshadow       int32
-	gccheckmark    int32
-	sbrk           int32
-	gcpacertrace   int32
+	allocfreetrace    int32
+	efence            int32
+	gccheckmark       int32
+	gcpacertrace      int32
+	gcshrinkstackoff  int32
+	gcstackbarrieroff int32
+	gcstoptheworld    int32
+	gctrace           int32
+	invalidptr        int32
+	sbrk              int32
+	scavenge          int32
+	scheddetail       int32
+	schedtrace        int32
+	wbshadow          int32
 }
 
 var dbgvars = []dbgVar{
 	{"allocfreetrace", &debug.allocfreetrace},
 	{"efence", &debug.efence},
-	{"gcdead", &debug.gcdead},
+	{"gccheckmark", &debug.gccheckmark},
+	{"gcpacertrace", &debug.gcpacertrace},
+	{"gcshrinkstackoff", &debug.gcshrinkstackoff},
+	{"gcstackbarrieroff", &debug.gcstackbarrieroff},
+	{"gcstoptheworld", &debug.gcstoptheworld},
 	{"gctrace", &debug.gctrace},
 	{"invalidptr", &debug.invalidptr},
+	{"sbrk", &debug.sbrk},
 	{"scavenge", &debug.scavenge},
 	{"scheddetail", &debug.scheddetail},
 	{"schedtrace", &debug.schedtrace},
 	{"wbshadow", &debug.wbshadow},
-	{"gccheckmark", &debug.gccheckmark},
-	{"sbrk", &debug.sbrk},
-	{"gcpacertrace", &debug.gcpacertrace},
 }
 
 func parsedebugvars() {
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index 1965e9e..933e3d0 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -826,6 +826,10 @@
 		throw("missing stack in shrinkstack")
 	}
 
+	if debug.gcshrinkstackoff > 0 {
+		return
+	}
+
 	oldsize := gp.stackAlloc
 	newsize := oldsize / 2
 	if newsize < _FixedStack {