runtime: don't use pointers in g_ucontext_t or stackcontext

The g_ucontext_t type holds registers saved for a goroutine.  We have
to scan it for pointers, but since registers don't necessarily hold
pointers we have to scan it conservatively.  That means that it should
not have a pointer type, since the GC will always scan pointers.
Instead it needs special treatment to be scanned conservatively.
The current GC doesn't care when a pointer type holds a non-pointer,
but the Go 1.8 GC does.

For the current GC this means we have to explicitly scan the
g_ucontext_t values in a G.

While we're at it change stackcontext to be uintptr too.  The entries
in stackcontext never hold pointers that the Go GC cares about.

Change-Id: I10c9dab28ce8b992be1a61c9be681af1c35c256e
Reviewed-on: https://go-review.googlesource.com/41270
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/libgo/go/runtime/runtime2.go b/libgo/go/runtime/runtime2.go
index 69769f9..9c5def2 100644
--- a/libgo/go/runtime/runtime2.go
+++ b/libgo/go/runtime/runtime2.go
@@ -418,8 +418,8 @@
 
 	traceback *tracebackg // stack traceback buffer
 
-	context      g_ucontext_t       // saved context for setcontext
-	stackcontext [10]unsafe.Pointer // split-stack context
+	context      g_ucontext_t // saved context for setcontext
+	stackcontext [10]uintptr  // split-stack context
 }
 
 type m struct {
@@ -787,7 +787,7 @@
 // aligned to a 16-byte boundary.  We implement this by increasing the
 // required size and picking an appropriate offset when we use the
 // array.
-type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
+type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(uintptr(0))]uintptr
 
 // sigset is the Go version of the C type sigset_t.
 // _sigset_t is defined by the Makefile from <signal.h>.
diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c
index 711f71e..ad29662 100644
--- a/libgo/runtime/go-signal.c
+++ b/libgo/runtime/go-signal.c
@@ -91,7 +91,7 @@
 
 	__splitstack_getcontext(&stack_context[0]);
 
-	stack = __splitstack_find_context(&gp->m->gsignal->stackcontext[0],
+	stack = __splitstack_find_context((void*)(&gp->m->gsignal->stackcontext[0]),
 					  &stack_size, &next_segment,
 					  &next_sp, &initial_sp);
 
@@ -126,7 +126,7 @@
 	// Set the split stack context so that the stack guards are
 	// checked correctly.
 
-	__splitstack_setcontext(&gp->m->gsignal->stackcontext[0]);
+	__splitstack_setcontext((void*)(&gp->m->gsignal->stackcontext[0]));
 
 	sigtrampgo(sig, info, context);
 
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 8e7d7ef..9a15a1d 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -1452,6 +1452,12 @@
 		break;
 	}
 
+	// Explicitly scan the saved contexts.
+	// We have to pass defaultProg to prevent scanblock from looking
+	// up the pointer to get the type.
+	enqueue1(wbufp, (Obj){(byte*)(&gp->gcregs[0]), sizeof(gp->gcregs), (uintptr)(&defaultProg[0])});
+	enqueue1(wbufp, (Obj){(byte*)(&gp->context[0]), sizeof(gp->context), (uintptr)(&defaultProg[0])});
+
 #ifdef USING_SPLIT_STACK
 	M *mp;
 	void* sp;
@@ -1483,7 +1489,7 @@
 			next_sp = gp->gcnextsp;
 			initial_sp = gp->gcinitialsp;
 		} else {
-			sp = __splitstack_find_context(&gp->stackcontext[0],
+			sp = __splitstack_find_context((void*)(&gp->stackcontext[0]),
 						       &spsize, &next_segment,
 						       &next_sp, &initial_sp);
 		}
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index 5febe0c..fb40797 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -181,7 +181,7 @@
 // So we make the field larger in runtime2.go and pick an appropriate
 // offset within the field here.
 static ucontext_t*
-ucontext_arg(void** go_ucontext)
+ucontext_arg(uintptr* go_ucontext)
 {
 	uintptr_t p = (uintptr_t)go_ucontext;
 	size_t align = __alignof__(ucontext_t);
@@ -279,7 +279,7 @@
 runtime_gogo(G* newg)
 {
 #ifdef USING_SPLIT_STACK
-	__splitstack_setcontext(&newg->stackcontext[0]);
+	__splitstack_setcontext((void*)(&newg->stackcontext[0]));
 #endif
 	g = newg;
 	newg->fromgogo = true;
@@ -314,7 +314,7 @@
 	if(gp != nil) {
 
 #ifdef USING_SPLIT_STACK
-		__splitstack_getcontext(&g->stackcontext[0]);
+		__splitstack_getcontext((void*)(&g->stackcontext[0]));
 #else
 		// We have to point to an address on the stack that is
 		// below the saved registers.
@@ -338,7 +338,7 @@
 	}
 	if (gp == nil || !gp->fromgogo) {
 #ifdef USING_SPLIT_STACK
-		__splitstack_setcontext(&mp->g0->stackcontext[0]);
+		__splitstack_setcontext((void*)(&mp->g0->stackcontext[0]));
 #endif
 		mp->g0->entry = fv;
 		mp->g0->param = gp;
@@ -431,7 +431,7 @@
 void getTraceback(G* me, G* gp)
 {
 #ifdef USING_SPLIT_STACK
-	__splitstack_getcontext(&me->stackcontext[0]);
+	__splitstack_getcontext((void*)(&me->stackcontext[0]));
 #endif
 	getcontext(ucontext_arg(&me->context[0]));
 
@@ -483,7 +483,7 @@
 	// Once we call schedule we're never coming back,
 	// so other calls can reuse this stack space.
 #ifdef USING_SPLIT_STACK
-	__splitstack_getcontext(&gp->stackcontext[0]);
+	__splitstack_getcontext((void*)(&gp->stackcontext[0]));
 #else
 	gp->gcinitialsp = &arg;
 	// Setting gcstacksize to 0 is a marker meaning that gcinitialsp
@@ -553,7 +553,7 @@
 	gp->entry = nil;
 	gp->param = nil;
 #ifdef USING_SPLIT_STACK
-	__splitstack_getcontext(&gp->stackcontext[0]);
+	__splitstack_getcontext((void*)(&gp->stackcontext[0]));
 	val = 0;
 	__splitstack_block_signals(&val, nil);
 #else
@@ -715,10 +715,10 @@
 
 #if USING_SPLIT_STACK
 		*ret_stack = __splitstack_makecontext(stacksize,
-						      &newg->stackcontext[0],
+						      (void*)(&newg->stackcontext[0]),
 						      &ss_stacksize);
 		*ret_stacksize = (uintptr)ss_stacksize;
-		__splitstack_block_signals_context(&newg->stackcontext[0],
+		__splitstack_block_signals_context((void*)(&newg->stackcontext[0]),
 						   &dont_block_signals, nil);
 #else
                 // In 64-bit mode, the maximum Go allocation space is
@@ -756,9 +756,9 @@
   int dont_block_signals = 0;
   size_t ss_spsize;
 
-  *sp = __splitstack_resetcontext(&newg->stackcontext[0], &ss_spsize);
+  *sp = __splitstack_resetcontext((void*)(&newg->stackcontext[0]), &ss_spsize);
   *spsize = ss_spsize;
-  __splitstack_block_signals_context(&newg->stackcontext[0],
+  __splitstack_block_signals_context((void*)(&newg->stackcontext[0]),
 				     &dont_block_signals, nil);
 #else
   *sp = newg->gcinitialsp;