This libgo patch by Cherry Zhang adds some noescape cases to the runtime package. This is in preparation of turning on escape analysis for the runtime.
- In gccgo, systemstack is implemented with mcall, which is not go:noescape. Wrap the closure in noescape so the escape analysis does not think it escapes. - Mark some C functions go:noescape. They do not leak arguments. - Use noescape function to make a few local variables' addresses not escape. The escape analysis cannot figure out because they are assigned to pointer indirections. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 256417) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -8e20ba6b6c4906f2f0be4b0a1515d11e0f41fb29 +5cae6a4e0849a3586ee7ce9c915c1520a17db982 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: libgo/go/runtime/panic.go =================================================================== --- libgo/go/runtime/panic.go (revision 256366) +++ libgo/go/runtime/panic.go (working copy) @@ -201,7 +201,7 @@ func deferreturn(frame *bool) { // The gc compiler does this using assembler // code in jmpdefer. var fn func(unsafe.Pointer) - *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(unsafe.Pointer(&pfn)) + *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) fn(d.arg) } @@ -264,7 +264,7 @@ func checkdefer(frame *bool) { var p _panic p.isforeign = true p.link = gp._panic - gp._panic = &p + gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) for { d := gp._defer if d == nil || d.frame != frame || d.pfn == 0 { @@ -275,7 +275,7 @@ func checkdefer(frame *bool) { gp._defer = d.link var fn func(unsafe.Pointer) - *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(unsafe.Pointer(&pfn)) + *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) fn(d.arg) freedefer(d) @@ -368,7 +368,7 @@ func Goexit() { d.pfn = 0 var fn func(unsafe.Pointer) - *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(unsafe.Pointer(&pfn)) + *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) fn(d.arg) if gp._defer != d { @@ -491,7 +491,7 @@ func gopanic(e interface{}) { d._panic = p var fn func(unsafe.Pointer) - *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(unsafe.Pointer(&pfn)) + *(*uintptr)(unsafe.Pointer(&fn)) = uintptr(noescape(unsafe.Pointer(&pfn))) fn(d.arg) if gp._defer != d { Index: libgo/go/runtime/proc.go =================================================================== --- libgo/go/runtime/proc.go (revision 256366) +++ libgo/go/runtime/proc.go (working copy) @@ -46,7 +46,11 @@ import ( // C functions for thread and context management. func newosproc(*m) + +//go:noescape func malg(bool, bool, *unsafe.Pointer, *uintptr) *g + +//go:noescape func resetNewG(*g, *unsafe.Pointer, *uintptr) func gogo(*g) func setGContext() Index: libgo/go/runtime/signal_gccgo.go =================================================================== --- libgo/go/runtime/signal_gccgo.go (revision 256366) +++ libgo/go/runtime/signal_gccgo.go (working copy) @@ -13,24 +13,31 @@ import ( // Functions for gccgo to support signal handling. In the gc runtime // these are written in OS-specific files and in assembler. +//go:noescape //extern sigaction func sigaction(signum uint32, act *_sigaction, oact *_sigaction) int32 +//go:noescape //extern sigprocmask func sigprocmask(how int32, set *sigset, oldset *sigset) int32 +//go:noescape //extern sigfillset func sigfillset(set *sigset) int32 +//go:noescape //extern sigemptyset func sigemptyset(set *sigset) int32 +//go:noescape //extern sigaddset func c_sigaddset(set *sigset, signum uint32) int32 +//go:noescape //extern sigdelset func c_sigdelset(set *sigset, signum uint32) int32 +//go:noescape //extern sigaltstack func sigaltstack(ss *_stack_t, oss *_stack_t) int32 @@ -43,6 +50,7 @@ func getpid() _pid_t //extern kill func kill(pid _pid_t, sig uint32) int32 +//go:noescape //extern setitimer func setitimer(which int32, new *_itimerval, old *_itimerval) int32 Index: libgo/go/runtime/stubs.go =================================================================== --- libgo/go/runtime/stubs.go (revision 256366) +++ libgo/go/runtime/stubs.go (working copy) @@ -60,10 +60,11 @@ func systemstack(fn func()) { if gp == mp.g0 || gp == mp.gsignal { fn() } else if gp == mp.curg { - mcall(func(origg *g) { + fn1 := func(origg *g) { fn() gogo(origg) - }) + } + mcall(*(*func(*g))(noescape(unsafe.Pointer(&fn1)))) } else { badsystemstack() } @@ -160,6 +161,7 @@ func breakpoint() func asminit() {} //go:linkname reflectcall reflect.call +//go:noescape func reflectcall(fntype *functype, fn *funcval, isInterface, isMethod bool, params, results *unsafe.Pointer) func procyield(cycles uint32) @@ -355,7 +357,10 @@ func atomicstorep(ptr unsafe.Pointer, ne func getSigtramp() uintptr // The sa_handler field is generally hidden in a union, so use C accessors. +//go:noescape func getSigactionHandler(*_sigaction) uintptr + +//go:noescape func setSigactionHandler(*_sigaction, uintptr) // Retrieve fields from the siginfo_t and ucontext_t pointers passed Index: libgo/go/runtime/traceback_gccgo.go =================================================================== --- libgo/go/runtime/traceback_gccgo.go (revision 256366) +++ libgo/go/runtime/traceback_gccgo.go (working copy) @@ -9,7 +9,7 @@ package runtime import ( "runtime/internal/sys" - _ "unsafe" // for go:linkname + "unsafe" ) func printcreatedby(gp *g) { @@ -46,6 +46,7 @@ type location struct { lineno int } +//go:noescape //extern runtime_callers func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32 @@ -185,7 +186,7 @@ func tracebackothers(me *g) { if gp != nil && gp != me { print("\n") goroutineheader(gp) - gp.traceback = &tb + gp.traceback = (*tracebackg)(noescape(unsafe.Pointer(&tb))) getTraceback(me, gp) printtrace(tb.locbuf[:tb.c], nil) printcreatedby(gp) @@ -219,7 +220,7 @@ func tracebackothers(me *g) { print("\tgoroutine in C code; stack unavailable\n") printcreatedby(gp) } else { - gp.traceback = &tb + gp.traceback = (*tracebackg)(noescape(unsafe.Pointer(&tb))) getTraceback(me, gp) printtrace(tb.locbuf[:tb.c], nil) printcreatedby(gp)