From e4876be5f5c5524ea742527100e36c5095181b28 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 10 Jan 2018 05:15:52 +0000 Subject: [PATCH] runtime: noescape some functions/variables 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. Reviewed-on: https://go-review.googlesource.com/86244 From-SVN: r256418 --- gcc/go/gofrontend/MERGE | 2 +- libgo/go/runtime/panic.go | 10 +++++----- libgo/go/runtime/proc.go | 4 ++++ libgo/go/runtime/signal_gccgo.go | 8 ++++++++ libgo/go/runtime/stubs.go | 9 +++++++-- libgo/go/runtime/traceback_gccgo.go | 7 ++++--- 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f43c1daafe5..4404ee2598a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go index 5cc325f3954..b2deb6e6580 100644 --- a/libgo/go/runtime/panic.go +++ b/libgo/go/runtime/panic.go @@ -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 { diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 1ea41528600..515efaa7516 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -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() diff --git a/libgo/go/runtime/signal_gccgo.go b/libgo/go/runtime/signal_gccgo.go index 6fe7ba10aaf..92143ea6fbb 100644 --- a/libgo/go/runtime/signal_gccgo.go +++ b/libgo/go/runtime/signal_gccgo.go @@ -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 diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go index c454356b838..fa3b1ce9552 100644 --- a/libgo/go/runtime/stubs.go +++ b/libgo/go/runtime/stubs.go @@ -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, new unsafe.Pointer) { 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 diff --git a/libgo/go/runtime/traceback_gccgo.go b/libgo/go/runtime/traceback_gccgo.go index 79f78d8d247..8551ec19ac3 100644 --- a/libgo/go/runtime/traceback_gccgo.go +++ b/libgo/go/runtime/traceback_gccgo.go @@ -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) -- 2.30.2