// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package runtime import "unsafe" var indexError = error(errorString("index out of range")) func panicindex() { panic(indexError) } var sliceError = error(errorString("slice bounds out of range")) func panicslice() { panic(sliceError) } var divideError = error(errorString("integer divide by zero")) func panicdivide() { panic(divideError) } func throwreturn() { gothrow("no return at end of a typed function - compiler is broken") } func throwinit() { gothrow("recursive call during initialization - linker skew") } // Create a new deferred function fn with siz bytes of arguments. // The compiler turns a defer statement into a call to this. //go:nosplit func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn // the arguments of fn are in a perilous state. The stack map // for deferproc does not describe them. So we can't let garbage // collection or stack copying trigger until we've copied them out // to somewhere safe. deferproc_m does that. Until deferproc_m, // we can only call nosplit routines. argp := uintptr(unsafe.Pointer(&fn)) argp += unsafe.Sizeof(fn) if GOARCH == "arm" { argp += ptrSize // skip caller's saved link register } mp := acquirem() mp.scalararg[0] = uintptr(siz) mp.ptrarg[0] = unsafe.Pointer(fn) mp.scalararg[1] = argp mp.scalararg[2] = getcallerpc(unsafe.Pointer(&siz)) if mp.curg != getg() { // go code on the m stack can't defer gothrow("defer on m") } onM(deferproc_m) releasem(mp) // deferproc returns 0 normally. // a deferred func that stops a panic // makes the deferproc return 1. // the code the compiler generates always // checks the return value and jumps to the // end of the function if deferproc returns != 0. return0() // No code can go here - the C return register has // been set and must not be clobbered. } // Each P holds pool for defers with arg sizes 8, 24, 40, 56 and 72 bytes. // Memory block is 40 (24 for 32 bits) bytes larger due to Defer header. // This maps exactly to malloc size classes. // defer size class for arg size sz func deferclass(siz uintptr) uintptr { return (siz + 7) >> 4 } // total size of memory block for defer with arg size sz func totaldefersize(siz uintptr) uintptr { return (unsafe.Sizeof(_defer{}) - unsafe.Sizeof(_defer{}.args)) + round(siz, ptrSize) } // Ensure that defer arg sizes that map to the same defer size class // also map to the same malloc size class. func testdefersizes() { var m [len(p{}.deferpool)]int32 for i := range m { m[i] = -1 } for i := uintptr(0); ; i++ { defersc := deferclass(i) if defersc >= uintptr(len(m)) { break } siz := goroundupsize(totaldefersize(i)) if m[defersc] < 0 { m[defersc] = int32(siz) continue } if m[defersc] != int32(siz) { print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n") gothrow("bad defer size class") } } } // Allocate a Defer, usually using per-P pool. // Each defer must be released with freedefer. // Note: runs on M stack func newdefer(siz int32) *_defer { var d *_defer sc := deferclass(uintptr(siz)) mp := acquirem() if sc < uintptr(len(p{}.deferpool)) { pp := mp.p d = pp.deferpool[sc] if d != nil { pp.deferpool[sc] = d.link } } if d == nil { // deferpool is empty or just a big defer total := goroundupsize(totaldefersize(uintptr(siz))) d = (*_defer)(gomallocgc(total, conservative, 0)) } d.siz = siz d.special = false gp := mp.curg d.link = gp._defer gp._defer = d releasem(mp) return d } // Free the given defer. // The defer cannot be used after this call. func freedefer(d *_defer) { if d.special { return } sc := deferclass(uintptr(d.siz)) if sc < uintptr(len(p{}.deferpool)) { mp := acquirem() pp := mp.p d.link = pp.deferpool[sc] pp.deferpool[sc] = d releasem(mp) // No need to wipe out pointers in argp/pc/fn/args, // because we empty the pool before GC. } } // Run a deferred function if there is one. // The compiler inserts a call to this at the end of any // function which calls defer. // If there is a deferred function, this will call runtime·jmpdefer, // which will jump to the deferred function such that it appears // to have been called by the caller of deferreturn at the point // just before deferreturn was called. The effect is that deferreturn // is called again and again until there are no more deferred functions. // Cannot split the stack because we reuse the caller's frame to // call the deferred function. // The single argument isn't actually used - it just has its address // taken so it can be matched against pending defers. //go:nosplit func deferreturn(arg0 uintptr) { gp := getg() d := gp._defer if d == nil { return } argp := uintptr(unsafe.Pointer(&arg0)) if d.argp != argp { return } // Moving arguments around. // Do not allow preemption here, because the garbage collector // won't know the form of the arguments until the jmpdefer can // flip the PC over to fn. mp := acquirem() memmove(unsafe.Pointer(argp), unsafe.Pointer(&d.args), uintptr(d.siz)) fn := d.fn gp._defer = d.link freedefer(d) releasem(mp) jmpdefer(fn, argp) } // Goexit terminates the goroutine that calls it. No other goroutine is affected. // Goexit runs all deferred calls before terminating the goroutine. // // Calling Goexit from the main goroutine terminates that goroutine // without func main returning. Since func main has not returned, // the program continues execution of other goroutines. // If all other goroutines exit, the program crashes. func Goexit() { // Run all deferred functions for the current goroutine. gp := getg() for gp._defer != nil { d := gp._defer gp._defer = d.link reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz)) freedefer(d) // Note: we ignore recovers here because Goexit isn't a panic } goexit() }