123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- // 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)
- }
- var overflowError = error(errorString("integer overflow"))
- func panicoverflow() {
- panic(overflowError)
- }
- var floatError = error(errorString("floating point error"))
- func panicfloat() {
- panic(floatError)
- }
- var memoryError = error(errorString("invalid memory address or nil pointer dereference"))
- func panicmem() {
- panic(memoryError)
- }
- 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.
- }
- // 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.
- const (
- deferHeaderSize = unsafe.Sizeof(_defer{})
- minDeferAlloc = (deferHeaderSize + 15) &^ 15
- minDeferArgs = minDeferAlloc - deferHeaderSize
- )
- // defer size class for arg size sz
- //go:nosplit
- func deferclass(siz uintptr) uintptr {
- if siz <= minDeferArgs {
- return 0
- }
- return (siz - minDeferArgs + 15) / 16
- }
- // total size of memory block for defer with arg size sz
- func totaldefersize(siz uintptr) uintptr {
- if siz <= minDeferArgs {
- return minDeferAlloc
- }
- return deferHeaderSize + siz
- }
- // 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")
- }
- }
- }
- // The arguments associated with a deferred call are stored
- // immediately after the _defer header in memory.
- //go:nosplit
- func deferArgs(d *_defer) unsafe.Pointer {
- return add(unsafe.Pointer(d), unsafe.Sizeof(*d))
- }
- var deferType *_type // type of _defer struct
- func init() {
- var x interface{}
- x = (*_defer)(nil)
- deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem
- }
- // 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 {
- // Allocate new defer+args.
- total := goroundupsize(totaldefersize(uintptr(siz)))
- d = (*_defer)(mallocgc(total, deferType, 0))
- }
- d.siz = siz
- 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.
- //go:nosplit
- func freedefer(d *_defer) {
- if d._panic != nil {
- freedeferpanic()
- }
- if d.fn != nil {
- freedeferfn()
- }
- sc := deferclass(uintptr(d.siz))
- if sc < uintptr(len(p{}.deferpool)) {
- mp := acquirem()
- pp := mp.p
- *d = _defer{}
- d.link = pp.deferpool[sc]
- pp.deferpool[sc] = d
- releasem(mp)
- }
- }
- // Separate function so that it can split stack.
- // Windows otherwise runs out of stack space.
- func freedeferpanic() {
- // _panic must be cleared before d is unlinked from gp.
- gothrow("freedefer with d._panic != nil")
- }
- func freedeferfn() {
- // fn must be cleared before d is unlinked from gp.
- gothrow("freedefer with d.fn != nil")
- }
- // 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), deferArgs(d), uintptr(d.siz))
- fn := d.fn
- d.fn = nil
- 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. Because Goexit
- // is not panic, however, any recover calls in those deferred functions will return nil.
- //
- // 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.
- // This code is similar to gopanic, see that implementation
- // for detailed comments.
- gp := getg()
- for {
- d := gp._defer
- if d == nil {
- break
- }
- if d.started {
- if d._panic != nil {
- d._panic.aborted = true
- d._panic = nil
- }
- d.fn = nil
- gp._defer = d.link
- freedefer(d)
- continue
- }
- d.started = true
- reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
- if gp._defer != d {
- gothrow("bad defer entry in Goexit")
- }
- d._panic = nil
- d.fn = nil
- gp._defer = d.link
- freedefer(d)
- // Note: we ignore recovers here because Goexit isn't a panic
- }
- goexit()
- }
- func canpanic(*g) bool
- // Print all currently active panics. Used when crashing.
- func printpanics(p *_panic) {
- if p.link != nil {
- printpanics(p.link)
- print("\t")
- }
- print("panic: ")
- printany(p.arg)
- if p.recovered {
- print(" [recovered]")
- }
- print("\n")
- }
- // The implementation of the predeclared function panic.
- func gopanic(e interface{}) {
- gp := getg()
- if gp.m.curg != gp {
- gothrow("panic on m stack")
- }
- // m.softfloat is set during software floating point.
- // It increments m.locks to avoid preemption.
- // We moved the memory loads out, so there shouldn't be
- // any reason for it to panic anymore.
- if gp.m.softfloat != 0 {
- gp.m.locks--
- gp.m.softfloat = 0
- gothrow("panic during softfloat")
- }
- if gp.m.mallocing != 0 {
- print("panic: ")
- printany(e)
- print("\n")
- gothrow("panic during malloc")
- }
- if gp.m.gcing != 0 {
- print("panic: ")
- printany(e)
- print("\n")
- gothrow("panic during gc")
- }
- if gp.m.locks != 0 {
- print("panic: ")
- printany(e)
- print("\n")
- gothrow("panic holding locks")
- }
- var p _panic
- p.arg = e
- p.link = gp._panic
- gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
- for {
- d := gp._defer
- if d == nil {
- break
- }
- // If defer was started by earlier panic or Goexit (and, since we're back here, that triggered a new panic),
- // take defer off list. The earlier panic or Goexit will not continue running.
- if d.started {
- if d._panic != nil {
- d._panic.aborted = true
- }
- d._panic = nil
- d.fn = nil
- gp._defer = d.link
- freedefer(d)
- continue
- }
- // Mark defer as started, but keep on list, so that traceback
- // can find and update the defer's argument frame if stack growth
- // or a garbage collection hapens before reflectcall starts executing d.fn.
- d.started = true
- // Record the panic that is running the defer.
- // If there is a new panic during the deferred call, that panic
- // will find d in the list and will mark d._panic (this panic) aborted.
- d._panic = (*_panic)(noescape((unsafe.Pointer)(&p)))
- p.argp = unsafe.Pointer(getargp(0))
- reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
- p.argp = nil
- // reflectcall did not panic. Remove d.
- if gp._defer != d {
- gothrow("bad defer entry in panic")
- }
- d._panic = nil
- d.fn = nil
- gp._defer = d.link
- // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
- //GC()
- pc := d.pc
- argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy
- freedefer(d)
- if p.recovered {
- gp._panic = p.link
- // Aborted panics are marked but remain on the g.panic list.
- // Remove them from the list.
- for gp._panic != nil && gp._panic.aborted {
- gp._panic = gp._panic.link
- }
- if gp._panic == nil { // must be done with signal
- gp.sig = 0
- }
- // Pass information about recovering frame to recovery.
- gp.sigcode0 = uintptr(argp)
- gp.sigcode1 = pc
- mcall(recovery_m)
- gothrow("recovery failed") // mcall should not return
- }
- }
- // ran out of deferred calls - old-school panic now
- startpanic()
- printpanics(gp._panic)
- dopanic(0) // should not return
- *(*int)(nil) = 0 // not reached
- }
- // getargp returns the location where the caller
- // writes outgoing function call arguments.
- //go:nosplit
- func getargp(x int) uintptr {
- // x is an argument mainly so that we can return its address.
- // However, we need to make the function complex enough
- // that it won't be inlined. We always pass x = 0, so this code
- // does nothing other than keep the compiler from thinking
- // the function is simple enough to inline.
- if x > 0 {
- return getcallersp(unsafe.Pointer(&x)) * 0
- }
- return uintptr(noescape(unsafe.Pointer(&x)))
- }
- // The implementation of the predeclared function recover.
- // Cannot split the stack because it needs to reliably
- // find the stack segment of its caller.
- //
- // TODO(rsc): Once we commit to CopyStackAlways,
- // this doesn't need to be nosplit.
- //go:nosplit
- func gorecover(argp uintptr) interface{} {
- // Must be in a function running as part of a deferred call during the panic.
- // Must be called from the topmost function of the call
- // (the function used in the defer statement).
- // p.argp is the argument pointer of that topmost deferred function call.
- // Compare against argp reported by caller.
- // If they match, the caller is the one who can recover.
- gp := getg()
- p := gp._panic
- if p != nil && !p.recovered && argp == uintptr(p.argp) {
- p.recovered = true
- return p.arg
- }
- return nil
- }
- //go:nosplit
- func startpanic() {
- onM_signalok(startpanic_m)
- }
- //go:nosplit
- func dopanic(unused int) {
- gp := getg()
- mp := acquirem()
- mp.ptrarg[0] = unsafe.Pointer(gp)
- mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused))
- mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused))
- onM_signalok(dopanic_m) // should never return
- *(*int)(nil) = 0
- }
- //go:nosplit
- func throw(s *byte) {
- gp := getg()
- if gp.m.throwing == 0 {
- gp.m.throwing = 1
- }
- startpanic()
- print("fatal error: ", gostringnocopy(s), "\n")
- dopanic(0)
- *(*int)(nil) = 0 // not reached
- }
- //go:nosplit
- func gothrow(s string) {
- gp := getg()
- if gp.m.throwing == 0 {
- gp.m.throwing = 1
- }
- startpanic()
- print("fatal error: ", s, "\n")
- dopanic(0)
- *(*int)(nil) = 0 // not reached
- }
|