From 40bff82885b8de850f909f38357c53670562f815 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Sat, 3 Oct 2020 20:40:49 -0400 Subject: runtime: define and use call16 everywhere Currently, runtime.call16 is defined and used only on 32-bit architectures, while 64-bit architectures all start at call32 and go up from there. This led to unnecessary complexity because call16's prototype needed to be in a different file, separate from all of the other call* prototypes, which in turn led to it getting out of sync with the other call* prototypes. This CL adds call16 on 64-bit architectures, bringing them all into sync, and moves the call16 prototype to live with the others. Prior to CL 31655 (in 2016), call16 couldn't be implemented on 64-bit architectures because it needed at least four words of argument space to invoke "callwritebarrier" after copying back the results. CL 31655 changed the way call* invoked the write barrier in preparation for the hybrid barrier; since the hybrid barrier had to be invoked prior to copying back results, it needed a different solution that didn't reuse call*'s stack space. At this point, call16 was no longer a problem on 64-bit, but we never added it. Until now. Change-Id: Id10ade0e4f75c6ea76afa6229ddaee2b994c27dd Reviewed-on: https://go-review.googlesource.com/c/go/+/259339 Trust: Austin Clements Reviewed-by: Cherry Zhang --- src/runtime/stubs.go | 1 + 1 file changed, 1 insertion(+) (limited to 'src/runtime/stubs.go') diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index b891a12fdd..bd2514e862 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -271,6 +271,7 @@ func return0() // in asm_*.s // not called directly; definitions here supply type information for traceback. +func call16(typ, fn, arg unsafe.Pointer, n, retoffset uint32) func call32(typ, fn, arg unsafe.Pointer, n, retoffset uint32) func call64(typ, fn, arg unsafe.Pointer, n, retoffset uint32) func call128(typ, fn, arg unsafe.Pointer, n, retoffset uint32) -- cgit v1.2.1 From 39b527691495902279da7ac8405a070ded7dd4a2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 7 Jul 2020 09:07:16 -0400 Subject: net: remove dependency on math/rand Like we did for sync, let the runtime give net random numbers, to avoid forcing an import of math/rand for DNS. Change-Id: Iab3e64121d687d288a3961a8ccbcebe589047253 Reviewed-on: https://go-review.googlesource.com/c/go/+/241258 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- src/runtime/stubs.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/runtime/stubs.go') diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index bd2514e862..6290142a41 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -130,6 +130,9 @@ func fastrandn(n uint32) uint32 { //go:linkname sync_fastrand sync.fastrand func sync_fastrand() uint32 { return fastrand() } +//go:linkname net_fastrand net.fastrand +func net_fastrand() uint32 { return fastrand() } + // in internal/bytealg/equal_*.s //go:noescape func memequal(a, b unsafe.Pointer, size uintptr) bool -- cgit v1.2.1 From 30c18878730434027dbefd343aad74963a1fdc48 Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 1 Oct 2020 17:22:38 -0400 Subject: runtime,cmd/cgo: simplify C -> Go call path This redesigns the way calls work from C to exported Go functions. It removes several steps from the call path, makes cmd/cgo no longer sensitive to the Go calling convention, and eliminates the use of reflectcall from cgo. In order to avoid generating a large amount of FFI glue between the C and Go ABIs, the cgo tool has long depended on generating a C function that marshals the arguments into a struct, and then the actual ABI switch happens in functions with fixed signatures that simply take a pointer to this struct. In a way, this CL simply pushes this idea further. Currently, the cgo tool generates this argument struct in the exact layout of the Go stack frame and depends on reflectcall to unpack it into the appropriate Go call (even though it's actually reflectcall'ing a function generated by cgo). In this CL, we decouple this struct from the Go stack layout. Instead, cgo generates a Go function that takes the struct, unpacks it, and calls the exported function. Since this generated function has a generic signature (like the rest of the call path), we don't need reflectcall and can instead depend on the Go compiler itself to implement the call to the exported Go function. One complication is that syscall.NewCallback on Windows, which converts a Go function into a C function pointer, depends on cgocallback's current dynamic calling approach since the signatures of the callbacks aren't known statically. For this specific case, we continue to depend on reflectcall. Really, the current approach makes some overly simplistic assumptions about translating the C ABI to the Go ABI. Now we're at least in a much better position to do a proper ABI translation. For comparison, the current cgo call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> _cgoexp_GoF (generated Go function) -> cgocallback (in asm_*.s) -> cgocallback_gofunc (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> reflectcall (in asm_*.s) -> _cgoexpwrap_GoF (generated Go function) -> p.GoF Now the call path looks like: GoF (generated C function) -> crosscall2 (in cgo/asm_*.s) -> cgocallback (in asm_*.s) -> cgocallbackg (in cgocall.go) -> cgocallbackg1 (in cgocall.go) -> _cgoexp_GoF (generated Go function) -> p.GoF Notably: 1. We combine _cgoexp_GoF and _cgoexpwrap_GoF and move the combined operation to the end of the sequence. This combined function also handles reflectcall's previous role. 2. We combined cgocallback and cgocallback_gofunc since the only purpose of having both was to convert a raw PC into a Go function value. We instead construct the Go function value in cgocallbackg1. 3. cgocallbackg1 no longer reaches backwards through the stack to get the arguments to cgocallback_gofunc. Instead, we just pass the arguments down. 4. Currently, we need an explicit msanwrite to mark the results struct as written because reflectcall doesn't do this. Now, the results are written by regular Go assignments, so the Go compiler generates the necessary MSAN annotations. This also means we no longer need to track the size of the arguments frame. Updates #40724, since now we don't need to teach cgo about the register ABI or change how it uses reflectcall. Change-Id: I7840489a2597962aeb670e0c1798a16a7359c94f Reviewed-on: https://go-review.googlesource.com/c/go/+/258938 Trust: Austin Clements Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Zhang --- src/runtime/stubs.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'src/runtime/stubs.go') diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index 6290142a41..d77cb4d460 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -148,7 +148,13 @@ func noescape(p unsafe.Pointer) unsafe.Pointer { return unsafe.Pointer(x ^ 0) } -func cgocallback(fn, frame unsafe.Pointer, framesize, ctxt uintptr) +// Not all cgocallback frames are actually cgocallback, +// so not all have these arguments. Mark them uintptr so that the GC +// does not misinterpret memory when the arguments are not present. +// cgocallback is not called from Go, only from crosscall2. +// This in turn calls cgocallbackg, which is where we'll find +// pointer-declared arguments. +func cgocallback(fn, frame, ctxt uintptr) func gogo(buf *gobuf) func gosave(buf *gobuf) @@ -163,10 +169,11 @@ func breakpoint() // back into arg+retoffset before returning. If copying result bytes back, // the caller should pass the argument frame type as argtype, so that // call can execute appropriate write barriers during the copy. -// Package reflect passes a frame type. In package runtime, there is only -// one call that copies results back, in cgocallbackg1, and it does NOT pass a -// frame type, meaning there are no write barriers invoked. See that call -// site for justification. +// +// Package reflect always passes a frame type. In package runtime, +// Windows callbacks are the only use of this that copies results +// back, and those cannot have pointers in their results, so runtime +// passes nil for the frame type. // // Package reflect accesses this symbol through a linkname. func reflectcall(argtype *_type, fn, arg unsafe.Pointer, argsize uint32, retoffset uint32) @@ -187,14 +194,6 @@ type neverCallThisFunction struct{} // prematurely and if there is leftover state it may panic. func goexit(neverCallThisFunction) -// Not all cgocallback_gofunc frames are actually cgocallback_gofunc, -// so not all have these arguments. Mark them uintptr so that the GC -// does not misinterpret memory when the arguments are not present. -// cgocallback_gofunc is not called from go, only from cgocallback, -// so the arguments will be found via cgocallback's pointer-declared arguments. -// See the assembly implementations for more details. -func cgocallback_gofunc(fv, frame, framesize, ctxt uintptr) - // publicationBarrier performs a store/store barrier (a "publication" // or "export" barrier). Some form of synchronization is required // between initializing an object and making that object accessible to -- cgit v1.2.1