runtime: change g's in systemstack

The systemstack function in the gc toolchain changes to a different g.
This is often used to get more stack space; the gofrontend uses a
different stack growth mechanism that does not require changing g's,
so we've been running with a version of systemstack that keeps the
same g.  However, the garbage collector has various tests to verify
that it is running on g0 rather than on a normal g.  For simplicity,
change the gofrontend version of systemstack to change to a different
g just as the gc toolchain does.

This permits us to uncomment some sanity checks in notetsleep.
Doing that requires us to fix up a couple of places where C code calls
{start,stop}TheWorldWithSema while not on g0.

Note that this does slow down some code in the runtime package unnecessarily.
It may be useful to find some places where the runtime calls
systemstack only to get more stack space and change it to use some
other function.  That other function would act like systemstack in the
gc toolchain but simply call the argument in the gofrontend.

Change-Id: I6ec58c70bcca91d518d250ec338677b26bb7e5a6
Reviewed-on: https://go-review.googlesource.com/40973
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/libgo/go/runtime/lock_futex.go b/libgo/go/runtime/lock_futex.go
index 4d914b2..9877bc3 100644
--- a/libgo/go/runtime/lock_futex.go
+++ b/libgo/go/runtime/lock_futex.go
@@ -198,13 +198,10 @@
 }
 
 func notetsleep(n *note, ns int64) bool {
-	// Currently OK to sleep in non-g0 for gccgo.  It happens in
-	// stoptheworld because our version of systemstack does not
-	// change to g0.
-	// gp := getg()
-	// if gp != gp.m.g0 && gp.m.preemptoff != "" {
-	//	throw("notetsleep not on g0")
-	// }
+	gp := getg()
+	if gp != gp.m.g0 && gp.m.preemptoff != "" {
+		throw("notetsleep not on g0")
+	}
 
 	return notetsleep_internal(n, ns)
 }
diff --git a/libgo/go/runtime/lock_sema.go b/libgo/go/runtime/lock_sema.go
index e2d7614..57fee19 100644
--- a/libgo/go/runtime/lock_sema.go
+++ b/libgo/go/runtime/lock_sema.go
@@ -251,14 +251,9 @@
 
 func notetsleep(n *note, ns int64) bool {
 	gp := getg()
-
-	// Currently OK to sleep in non-g0 for gccgo.  It happens in
-	// stoptheworld because our version of systemstack does not
-	// change to g0.
-	// if gp != gp.m.g0 && gp.m.preemptoff != "" {
-	//	throw("notetsleep not on g0")
-	// }
-
+	if gp != gp.m.g0 && gp.m.preemptoff != "" {
+		throw("notetsleep not on g0")
+	}
 	semacreate(gp.m)
 	return notetsleep_internal(n, ns, nil, 0)
 }
diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go
index 0907afc..28fbe5b 100644
--- a/libgo/go/runtime/proc.go
+++ b/libgo/go/runtime/proc.go
@@ -32,8 +32,6 @@
 //go:linkname exitsyscall runtime.exitsyscall
 //go:linkname gfget runtime.gfget
 //go:linkname helpgc runtime.helpgc
-//go:linkname stopTheWorldWithSema runtime.stopTheWorldWithSema
-//go:linkname startTheWorldWithSema runtime.startTheWorldWithSema
 //go:linkname kickoff runtime.kickoff
 //go:linkname mstart1 runtime.mstart1
 //go:linkname globrunqput runtime.globrunqput
diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go
index cccbd12..9109e4b 100644
--- a/libgo/go/runtime/stubs.go
+++ b/libgo/go/runtime/stubs.go
@@ -51,11 +51,22 @@
 //
 // For the gc toolchain this permits running a function that requires
 // additional stack space in a context where the stack can not be
-// split.  For gccgo, however, stack splitting is not managed by the
-// Go runtime. In effect, all stacks are system stacks. So this gccgo
-// version just runs the function.
+// split. We don't really need additional stack space in gccgo, since
+// stack splitting is handled separately. But to keep things looking
+// the same, we do switch to the g0 stack here if necessary.
 func systemstack(fn func()) {
-	fn()
+	gp := getg()
+	mp := gp.m
+	if gp == mp.g0 || gp == mp.gsignal {
+		fn()
+	} else if gp == mp.curg {
+		mcall(func(origg *g) {
+			fn()
+			gogo(origg)
+		})
+	} else {
+		badsystemstack()
+	}
 }
 
 func badsystemstack() {
@@ -656,3 +667,15 @@
 
 // Temporary for gccgo until we port malloc.go.
 const maxTinySize = 16
+
+// Temporary for gccgo until we port heapdump.go and mgc.go.
+//go:linkname callStopTheWorldWithSema runtime.callStopTheWorldWithSema
+func callStopTheWorldWithSema() {
+	systemstack(stopTheWorldWithSema)
+}
+
+// Temporary for gccgo until we port heapdump.go and mgc.go.
+//go:linkname callStartTheWorldWithSema runtime.callStartTheWorldWithSema
+func callStartTheWorldWithSema() {
+	systemstack(startTheWorldWithSema)
+}
diff --git a/libgo/runtime/heapdump.c b/libgo/runtime/heapdump.c
index ab65d39..8178946 100644
--- a/libgo/runtime/heapdump.c
+++ b/libgo/runtime/heapdump.c
@@ -621,7 +621,7 @@
 	runtime_acquireWorldsema();
 	m = runtime_m();
 	m->preemptoff = runtime_gostringnocopy((const byte*)"write heap dump");
-	runtime_stopTheWorldWithSema();
+	runtime_callStopTheWorldWithSema();
 
 	// Update stats so we can dump them.
 	// As a side effect, flushes all the MCaches so the MSpan.freelist
@@ -641,7 +641,7 @@
 	dumpfd = 0;
 
 	// Start up the world again.
-	runtime_startTheWorldWithSema();
+	runtime_callStartTheWorldWithSema();
 	runtime_releaseWorldsema();
 	m->preemptoff = runtime_gostringnocopy(nil);
 }
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 13e04f0..0178507 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -2097,7 +2097,7 @@
 	a.start_time = runtime_nanotime();
 	a.eagersweep = force >= 2;
 	m->gcing = 1;
-	runtime_stopTheWorldWithSema();
+	runtime_callStopTheWorldWithSema();
 	
 	clearpools();
 
@@ -2122,7 +2122,7 @@
 	m->gcing = 0;
 	m->locks++;
 	runtime_releaseWorldsema();
-	runtime_startTheWorldWithSema();
+	runtime_callStartTheWorldWithSema();
 	m->locks--;
 
 	// now that gc is done, kick off finalizer thread if needed
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index e38bf06..e12d506 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -382,10 +382,10 @@
 void	runtime_iterate_finq(void (*callback)(FuncVal*, void*, const FuncType*, const PtrType*))
   __asm__(GOSYM_PREFIX "runtime.iterate_finq");
 
-void	runtime_stopTheWorldWithSema(void)
-  __asm__(GOSYM_PREFIX "runtime.stopTheWorldWithSema");
-void	runtime_startTheWorldWithSema(void)
-  __asm__(GOSYM_PREFIX "runtime.startTheWorldWithSema");
+void	runtime_callStopTheWorldWithSema(void)
+  __asm__(GOSYM_PREFIX "runtime.callStopTheWorldWithSema");
+void	runtime_callStartTheWorldWithSema(void)
+  __asm__(GOSYM_PREFIX "runtime.callStartTheWorldWithSema");
 void	runtime_acquireWorldsema(void)
   __asm__(GOSYM_PREFIX "runtime.acquireWorldsema");
 void	runtime_releaseWorldsema(void)