From 8f296f59de0703b0559474beb434a265e277bdca Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 8 Jun 2019 17:20:57 +0000 Subject: Revert "Revert "cmd/compile,runtime: allocate defer records on the stack"" This reverts CL 180761 Reason for revert: Reinstate the stack-allocated defer CL. There was nothing wrong with the CL proper, but stack allocation of defers exposed two other issues. Issue #32477: Fix has been submitted as CL 181258. Issue #32498: Possible fix is CL 181377 (not submitted yet). Change-Id: I32b3365d5026600069291b068bbba6cb15295eb3 Reviewed-on: https://go-review.googlesource.com/c/go/+/181378 Reviewed-by: Brad Fitzpatrick --- src/runtime/panic.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'src/runtime/panic.go') diff --git a/src/runtime/panic.go b/src/runtime/panic.go index f39a4bc0a2..ce26eb540d 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -228,6 +228,46 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn // been set and must not be clobbered. } +// deferprocStack queues a new deferred function with a defer record on the stack. +// The defer record must have its siz and fn fields initialized. +// All other fields can contain junk. +// The defer record must be immediately followed in memory by +// the arguments of the defer. +// Nosplit because the arguments on the stack won't be scanned +// until the defer record is spliced into the gp._defer list. +//go:nosplit +func deferprocStack(d *_defer) { + gp := getg() + if gp.m.curg != gp { + // go code on the system stack can't defer + throw("defer on system stack") + } + // siz and fn are already set. + // The other fields are junk on entry to deferprocStack and + // are initialized here. + d.started = false + d.heap = false + d.sp = getcallersp() + d.pc = getcallerpc() + // The lines below implement: + // d.panic = nil + // d.link = gp._defer + // gp._defer = d + // But without write barriers. The first two are writes to + // the stack so they don't need a write barrier, and furthermore + // are to uninitialized memory, so they must not use a write barrier. + // The third write does not require a write barrier because we + // explicitly mark all the defer structures, so we don't need to + // keep track of pointers to them with a write barrier. + *(*uintptr)(unsafe.Pointer(&d._panic)) = 0 + *(*uintptr)(unsafe.Pointer(&d.link)) = uintptr(unsafe.Pointer(gp._defer)) + *(*uintptr)(unsafe.Pointer(&gp._defer)) = uintptr(unsafe.Pointer(d)) + + return0() + // No code can go here - the C return register has + // been set and must not be clobbered. +} + // Small malloc size classes >= 16 are the multiples of 16: 16, 32, 48, 64, 80, 96, 112, 128, 144, ... // Each P holds a pool for defers with small arg sizes. // Assign defer allocations to pools by rounding to 16, to match malloc size classes. @@ -349,6 +389,7 @@ func newdefer(siz int32) *_defer { } } d.siz = siz + d.heap = true d.link = gp._defer gp._defer = d return d @@ -368,6 +409,9 @@ func freedefer(d *_defer) { if d.fn != nil { freedeferfn() } + if !d.heap { + return + } sc := deferclass(uintptr(d.siz)) if sc >= uintptr(len(p{}.deferpool)) { return -- cgit v1.3-5-g9baa