diff options
| author | Keith Randall <khr@golang.org> | 2019-06-08 17:20:57 +0000 |
|---|---|---|
| committer | Keith Randall <khr@golang.org> | 2019-06-10 16:19:39 +0000 |
| commit | 8f296f59de0703b0559474beb434a265e277bdca (patch) | |
| tree | 4ffd97168a989aa958ef2055f07759f29a09210b /src/runtime/panic.go | |
| parent | daf944a531fecf2431b60da608e70680f4927412 (diff) | |
| download | go-8f296f59de0703b0559474beb434a265e277bdca.tar.xz | |
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 <bradfitz@golang.org>
Diffstat (limited to 'src/runtime/panic.go')
| -rw-r--r-- | src/runtime/panic.go | 44 |
1 files changed, 44 insertions, 0 deletions
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 |
