| // 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 ( | 
 | 	"runtime/internal/atomic" | 
 | 	"runtime/internal/sys" | 
 | 	"unsafe" | 
 | ) | 
 |  | 
 | // We have two different ways of doing defers. The older way involves creating a | 
 | // defer record at the time that a defer statement is executing and adding it to a | 
 | // defer chain. This chain is inspected by the deferreturn call at all function | 
 | // exits in order to run the appropriate defer calls. A cheaper way (which we call | 
 | // open-coded defers) is used for functions in which no defer statements occur in | 
 | // loops. In that case, we simply store the defer function/arg information into | 
 | // specific stack slots at the point of each defer statement, as well as setting a | 
 | // bit in a bitmask. At each function exit, we add inline code to directly make | 
 | // the appropriate defer calls based on the bitmask and fn/arg information stored | 
 | // on the stack. During panic/Goexit processing, the appropriate defer calls are | 
 | // made using extra funcdata info that indicates the exact stack slots that | 
 | // contain the bitmask and defer fn/args. | 
 |  | 
 | // Check to make sure we can really generate a panic. If the panic | 
 | // was generated from the runtime, or from inside malloc, then convert | 
 | // to a throw of msg. | 
 | // pc should be the program counter of the compiler-generated code that | 
 | // triggered this panic. | 
 | func panicCheck1(pc uintptr, msg string) { | 
 | 	if sys.GoarchWasm == 0 && hasPrefix(funcname(findfunc(pc)), "runtime.") { | 
 | 		// Note: wasm can't tail call, so we can't get the original caller's pc. | 
 | 		throw(msg) | 
 | 	} | 
 | 	// TODO: is this redundant? How could we be in malloc | 
 | 	// but not in the runtime? runtime/internal/*, maybe? | 
 | 	gp := getg() | 
 | 	if gp != nil && gp.m != nil && gp.m.mallocing != 0 { | 
 | 		throw(msg) | 
 | 	} | 
 | } | 
 |  | 
 | // Same as above, but calling from the runtime is allowed. | 
 | // | 
 | // Using this function is necessary for any panic that may be | 
 | // generated by runtime.sigpanic, since those are always called by the | 
 | // runtime. | 
 | func panicCheck2(err string) { | 
 | 	// panic allocates, so to avoid recursive malloc, turn panics | 
 | 	// during malloc into throws. | 
 | 	gp := getg() | 
 | 	if gp != nil && gp.m != nil && gp.m.mallocing != 0 { | 
 | 		throw(err) | 
 | 	} | 
 | } | 
 |  | 
 | // Many of the following panic entry-points turn into throws when they | 
 | // happen in various runtime contexts. These should never happen in | 
 | // the runtime, and if they do, they indicate a serious issue and | 
 | // should not be caught by user code. | 
 | // | 
 | // The panic{Index,Slice,divide,shift} functions are called by | 
 | // code generated by the compiler for out of bounds index expressions, | 
 | // out of bounds slice expressions, division by zero, and shift by negative. | 
 | // The panicdivide (again), panicoverflow, panicfloat, and panicmem | 
 | // functions are called by the signal handler when a signal occurs | 
 | // indicating the respective problem. | 
 | // | 
 | // Since panic{Index,Slice,shift} are never called directly, and | 
 | // since the runtime package should never have an out of bounds slice | 
 | // or array reference or negative shift, if we see those functions called from the | 
 | // runtime package we turn the panic into a throw. That will dump the | 
 | // entire runtime stack for easier debugging. | 
 | // | 
 | // The entry points called by the signal handler will be called from | 
 | // runtime.sigpanic, so we can't disallow calls from the runtime to | 
 | // these (they always look like they're called from the runtime). | 
 | // Hence, for these, we just check for clearly bad runtime conditions. | 
 | // | 
 | // The panic{Index,Slice} functions are implemented in assembly and tail call | 
 | // to the goPanic{Index,Slice} functions below. This is done so we can use | 
 | // a space-minimal register calling convention. | 
 |  | 
 | // failures in the comparisons for s[x], 0 <= x < y (y == len(s)) | 
 | func goPanicIndex(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "index out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsIndex}) | 
 | } | 
 | func goPanicIndexU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "index out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsIndex}) | 
 | } | 
 |  | 
 | // failures in the comparisons for s[:x], 0 <= x <= y (y == len(s) or cap(s)) | 
 | func goPanicSliceAlen(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAlen}) | 
 | } | 
 | func goPanicSliceAlenU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAlen}) | 
 | } | 
 | func goPanicSliceAcap(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceAcap}) | 
 | } | 
 | func goPanicSliceAcapU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceAcap}) | 
 | } | 
 |  | 
 | // failures in the comparisons for s[x:y], 0 <= x <= y | 
 | func goPanicSliceB(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSliceB}) | 
 | } | 
 | func goPanicSliceBU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSliceB}) | 
 | } | 
 |  | 
 | // failures in the comparisons for s[::x], 0 <= x <= y (y == len(s) or cap(s)) | 
 | func goPanicSlice3Alen(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Alen}) | 
 | } | 
 | func goPanicSlice3AlenU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Alen}) | 
 | } | 
 | func goPanicSlice3Acap(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3Acap}) | 
 | } | 
 | func goPanicSlice3AcapU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3Acap}) | 
 | } | 
 |  | 
 | // failures in the comparisons for s[:x:y], 0 <= x <= y | 
 | func goPanicSlice3B(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3B}) | 
 | } | 
 | func goPanicSlice3BU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3B}) | 
 | } | 
 |  | 
 | // failures in the comparisons for s[x:y:], 0 <= x <= y | 
 | func goPanicSlice3C(x int, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: true, y: y, code: boundsSlice3C}) | 
 | } | 
 | func goPanicSlice3CU(x uint, y int) { | 
 | 	panicCheck1(getcallerpc(), "slice bounds out of range") | 
 | 	panic(boundsError{x: int64(x), signed: false, y: y, code: boundsSlice3C}) | 
 | } | 
 |  | 
 | // Implemented in assembly, as they take arguments in registers. | 
 | // Declared here to mark them as ABIInternal. | 
 | func panicIndex(x int, y int) | 
 | func panicIndexU(x uint, y int) | 
 | func panicSliceAlen(x int, y int) | 
 | func panicSliceAlenU(x uint, y int) | 
 | func panicSliceAcap(x int, y int) | 
 | func panicSliceAcapU(x uint, y int) | 
 | func panicSliceB(x int, y int) | 
 | func panicSliceBU(x uint, y int) | 
 | func panicSlice3Alen(x int, y int) | 
 | func panicSlice3AlenU(x uint, y int) | 
 | func panicSlice3Acap(x int, y int) | 
 | func panicSlice3AcapU(x uint, y int) | 
 | func panicSlice3B(x int, y int) | 
 | func panicSlice3BU(x uint, y int) | 
 | func panicSlice3C(x int, y int) | 
 | func panicSlice3CU(x uint, y int) | 
 |  | 
 | var shiftError = error(errorString("negative shift amount")) | 
 |  | 
 | func panicshift() { | 
 | 	panicCheck1(getcallerpc(), "negative shift amount") | 
 | 	panic(shiftError) | 
 | } | 
 |  | 
 | var divideError = error(errorString("integer divide by zero")) | 
 |  | 
 | func panicdivide() { | 
 | 	panicCheck2("integer divide by zero") | 
 | 	panic(divideError) | 
 | } | 
 |  | 
 | var overflowError = error(errorString("integer overflow")) | 
 |  | 
 | func panicoverflow() { | 
 | 	panicCheck2("integer overflow") | 
 | 	panic(overflowError) | 
 | } | 
 |  | 
 | var floatError = error(errorString("floating point error")) | 
 |  | 
 | func panicfloat() { | 
 | 	panicCheck2("floating point error") | 
 | 	panic(floatError) | 
 | } | 
 |  | 
 | var memoryError = error(errorString("invalid memory address or nil pointer dereference")) | 
 |  | 
 | func panicmem() { | 
 | 	panicCheck2("invalid memory address or nil pointer dereference") | 
 | 	panic(memoryError) | 
 | } | 
 |  | 
 | func panicmemAddr(addr uintptr) { | 
 | 	panicCheck2("invalid memory address or nil pointer dereference") | 
 | 	panic(errorAddressString{msg: "invalid memory address or nil pointer dereference", addr: addr}) | 
 | } | 
 |  | 
 | // 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 | 
 | 	gp := getg() | 
 | 	if gp.m.curg != gp { | 
 | 		// go code on the system stack can't defer | 
 | 		throw("defer on system stack") | 
 | 	} | 
 |  | 
 | 	// 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. The memmove below does that. | 
 | 	// Until the copy completes, we can only call nosplit routines. | 
 | 	sp := getcallersp() | 
 | 	argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn) | 
 | 	callerpc := getcallerpc() | 
 |  | 
 | 	d := newdefer(siz) | 
 | 	if d._panic != nil { | 
 | 		throw("deferproc: d.panic != nil after newdefer") | 
 | 	} | 
 | 	d.link = gp._defer | 
 | 	gp._defer = d | 
 | 	d.fn = fn | 
 | 	d.pc = callerpc | 
 | 	d.sp = sp | 
 | 	switch siz { | 
 | 	case 0: | 
 | 		// Do nothing. | 
 | 	case sys.PtrSize: | 
 | 		*(*uintptr)(deferArgs(d)) = *(*uintptr)(unsafe.Pointer(argp)) | 
 | 	default: | 
 | 		memmove(deferArgs(d), unsafe.Pointer(argp), uintptr(siz)) | 
 | 	} | 
 |  | 
 | 	// 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. | 
 | } | 
 |  | 
 | // 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.openDefer = false | 
 | 	d.sp = getcallersp() | 
 | 	d.pc = getcallerpc() | 
 | 	d.framepc = 0 | 
 | 	d.varp = 0 | 
 | 	// The lines below implement: | 
 | 	//   d.panic = nil | 
 | 	//   d.fd = nil | 
 | 	//   d.link = gp._defer | 
 | 	//   gp._defer = d | 
 | 	// But without write barriers. The first three 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 fourth 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.fd)) = 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. | 
 |  | 
 | 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 := roundupsize(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") | 
 | 			throw("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 { | 
 | 	if d.siz == 0 { | 
 | 		// Avoid pointer past the defer allocation. | 
 | 		return nil | 
 | 	} | 
 | 	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.  The defer is not | 
 | // added to any defer chain yet. | 
 | // | 
 | // This must not grow the stack because there may be a frame without | 
 | // stack map information when this is called. | 
 | // | 
 | //go:nosplit | 
 | func newdefer(siz int32) *_defer { | 
 | 	var d *_defer | 
 | 	sc := deferclass(uintptr(siz)) | 
 | 	gp := getg() | 
 | 	if sc < uintptr(len(p{}.deferpool)) { | 
 | 		pp := gp.m.p.ptr() | 
 | 		if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil { | 
 | 			// Take the slow path on the system stack so | 
 | 			// we don't grow newdefer's stack. | 
 | 			systemstack(func() { | 
 | 				lock(&sched.deferlock) | 
 | 				for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil { | 
 | 					d := sched.deferpool[sc] | 
 | 					sched.deferpool[sc] = d.link | 
 | 					d.link = nil | 
 | 					pp.deferpool[sc] = append(pp.deferpool[sc], d) | 
 | 				} | 
 | 				unlock(&sched.deferlock) | 
 | 			}) | 
 | 		} | 
 | 		if n := len(pp.deferpool[sc]); n > 0 { | 
 | 			d = pp.deferpool[sc][n-1] | 
 | 			pp.deferpool[sc][n-1] = nil | 
 | 			pp.deferpool[sc] = pp.deferpool[sc][:n-1] | 
 | 		} | 
 | 	} | 
 | 	if d == nil { | 
 | 		// Allocate new defer+args. | 
 | 		systemstack(func() { | 
 | 			total := roundupsize(totaldefersize(uintptr(siz))) | 
 | 			d = (*_defer)(mallocgc(total, deferType, true)) | 
 | 		}) | 
 | 	} | 
 | 	d.siz = siz | 
 | 	d.heap = true | 
 | 	return d | 
 | } | 
 |  | 
 | // Free the given defer. | 
 | // The defer cannot be used after this call. | 
 | // | 
 | // This must not grow the stack because there may be a frame without a | 
 | // stack map when this is called. | 
 | // | 
 | //go:nosplit | 
 | func freedefer(d *_defer) { | 
 | 	if d._panic != nil { | 
 | 		freedeferpanic() | 
 | 	} | 
 | 	if d.fn != nil { | 
 | 		freedeferfn() | 
 | 	} | 
 | 	if !d.heap { | 
 | 		return | 
 | 	} | 
 | 	sc := deferclass(uintptr(d.siz)) | 
 | 	if sc >= uintptr(len(p{}.deferpool)) { | 
 | 		return | 
 | 	} | 
 | 	pp := getg().m.p.ptr() | 
 | 	if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) { | 
 | 		// Transfer half of local cache to the central cache. | 
 | 		// | 
 | 		// Take this slow path on the system stack so | 
 | 		// we don't grow freedefer's stack. | 
 | 		systemstack(func() { | 
 | 			var first, last *_defer | 
 | 			for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 { | 
 | 				n := len(pp.deferpool[sc]) | 
 | 				d := pp.deferpool[sc][n-1] | 
 | 				pp.deferpool[sc][n-1] = nil | 
 | 				pp.deferpool[sc] = pp.deferpool[sc][:n-1] | 
 | 				if first == nil { | 
 | 					first = d | 
 | 				} else { | 
 | 					last.link = d | 
 | 				} | 
 | 				last = d | 
 | 			} | 
 | 			lock(&sched.deferlock) | 
 | 			last.link = sched.deferpool[sc] | 
 | 			sched.deferpool[sc] = first | 
 | 			unlock(&sched.deferlock) | 
 | 		}) | 
 | 	} | 
 |  | 
 | 	// These lines used to be simply `*d = _defer{}` but that | 
 | 	// started causing a nosplit stack overflow via typedmemmove. | 
 | 	d.siz = 0 | 
 | 	d.started = false | 
 | 	d.openDefer = false | 
 | 	d.sp = 0 | 
 | 	d.pc = 0 | 
 | 	d.framepc = 0 | 
 | 	d.varp = 0 | 
 | 	d.fd = nil | 
 | 	// d._panic and d.fn must be nil already. | 
 | 	// If not, we would have called freedeferpanic or freedeferfn above, | 
 | 	// both of which throw. | 
 | 	d.link = nil | 
 |  | 
 | 	pp.deferpool[sc] = append(pp.deferpool[sc], d) | 
 | } | 
 |  | 
 | // 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. | 
 | 	throw("freedefer with d._panic != nil") | 
 | } | 
 |  | 
 | func freedeferfn() { | 
 | 	// fn must be cleared before d is unlinked from gp. | 
 | 	throw("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. | 
 | // | 
 | // Declared as nosplit, because the function should not be preempted once we start | 
 | // modifying the caller's frame in order to reuse the 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 | 
 | 	} | 
 | 	sp := getcallersp() | 
 | 	if d.sp != sp { | 
 | 		return | 
 | 	} | 
 | 	if d.openDefer { | 
 | 		done := runOpenDeferFrame(gp, d) | 
 | 		if !done { | 
 | 			throw("unfinished open-coded defers in deferreturn") | 
 | 		} | 
 | 		gp._defer = d.link | 
 | 		freedefer(d) | 
 | 		return | 
 | 	} | 
 |  | 
 | 	// Moving arguments around. | 
 | 	// | 
 | 	// Everything called after this point must be recursively | 
 | 	// nosplit because the garbage collector won't know the form | 
 | 	// of the arguments until the jmpdefer can flip the PC over to | 
 | 	// fn. | 
 | 	switch d.siz { | 
 | 	case 0: | 
 | 		// Do nothing. | 
 | 	case sys.PtrSize: | 
 | 		*(*uintptr)(unsafe.Pointer(&arg0)) = *(*uintptr)(deferArgs(d)) | 
 | 	default: | 
 | 		memmove(unsafe.Pointer(&arg0), deferArgs(d), uintptr(d.siz)) | 
 | 	} | 
 | 	fn := d.fn | 
 | 	d.fn = nil | 
 | 	gp._defer = d.link | 
 | 	freedefer(d) | 
 | 	// If the defer function pointer is nil, force the seg fault to happen | 
 | 	// here rather than in jmpdefer. gentraceback() throws an error if it is | 
 | 	// called with a callback on an LR architecture and jmpdefer is on the | 
 | 	// stack, because the stack trace can be incorrect in that case - see | 
 | 	// issue #8153). | 
 | 	_ = fn.fn | 
 | 	jmpdefer(fn, uintptr(unsafe.Pointer(&arg0))) | 
 | } | 
 |  | 
 | // 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 a panic, 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() | 
 |  | 
 | 	// Create a panic object for Goexit, so we can recognize when it might be | 
 | 	// bypassed by a recover(). | 
 | 	var p _panic | 
 | 	p.goexit = true | 
 | 	p.link = gp._panic | 
 | 	gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) | 
 |  | 
 | 	addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp())) | 
 | 	for { | 
 | 		d := gp._defer | 
 | 		if d == nil { | 
 | 			break | 
 | 		} | 
 | 		if d.started { | 
 | 			if d._panic != nil { | 
 | 				d._panic.aborted = true | 
 | 				d._panic = nil | 
 | 			} | 
 | 			if !d.openDefer { | 
 | 				d.fn = nil | 
 | 				gp._defer = d.link | 
 | 				freedefer(d) | 
 | 				continue | 
 | 			} | 
 | 		} | 
 | 		d.started = true | 
 | 		d._panic = (*_panic)(noescape(unsafe.Pointer(&p))) | 
 | 		if d.openDefer { | 
 | 			done := runOpenDeferFrame(gp, d) | 
 | 			if !done { | 
 | 				// We should always run all defers in the frame, | 
 | 				// since there is no panic associated with this | 
 | 				// defer that can be recovered. | 
 | 				throw("unfinished open-coded defers in Goexit") | 
 | 			} | 
 | 			if p.aborted { | 
 | 				// Since our current defer caused a panic and may | 
 | 				// have been already freed, just restart scanning | 
 | 				// for open-coded defers from this frame again. | 
 | 				addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp())) | 
 | 			} else { | 
 | 				addOneOpenDeferFrame(gp, 0, nil) | 
 | 			} | 
 | 		} else { | 
 |  | 
 | 			// Save the pc/sp in reflectcallSave(), so we can "recover" back to this | 
 | 			// loop if necessary. | 
 | 			reflectcallSave(&p, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz)) | 
 | 		} | 
 | 		if p.aborted { | 
 | 			// We had a recursive panic in the defer d we started, and | 
 | 			// then did a recover in a defer that was further down the | 
 | 			// defer chain than d. In the case of an outstanding Goexit, | 
 | 			// we force the recover to return back to this loop. d will | 
 | 			// have already been freed if completed, so just continue | 
 | 			// immediately to the next defer on the chain. | 
 | 			p.aborted = false | 
 | 			continue | 
 | 		} | 
 | 		if gp._defer != d { | 
 | 			throw("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 | 
 | 	} | 
 | 	goexit1() | 
 | } | 
 |  | 
 | // Call all Error and String methods before freezing the world. | 
 | // Used when crashing with panicking. | 
 | func preprintpanics(p *_panic) { | 
 | 	defer func() { | 
 | 		if recover() != nil { | 
 | 			throw("panic while printing panic value") | 
 | 		} | 
 | 	}() | 
 | 	for p != nil { | 
 | 		switch v := p.arg.(type) { | 
 | 		case error: | 
 | 			p.arg = v.Error() | 
 | 		case stringer: | 
 | 			p.arg = v.String() | 
 | 		} | 
 | 		p = p.link | 
 | 	} | 
 | } | 
 |  | 
 | // Print all currently active panics. Used when crashing. | 
 | // Should only be called after preprintpanics. | 
 | func printpanics(p *_panic) { | 
 | 	if p.link != nil { | 
 | 		printpanics(p.link) | 
 | 		if !p.link.goexit { | 
 | 			print("\t") | 
 | 		} | 
 | 	} | 
 | 	if p.goexit { | 
 | 		return | 
 | 	} | 
 | 	print("panic: ") | 
 | 	printany(p.arg) | 
 | 	if p.recovered { | 
 | 		print(" [recovered]") | 
 | 	} | 
 | 	print("\n") | 
 | } | 
 |  | 
 | // addOneOpenDeferFrame scans the stack for the first frame (if any) with | 
 | // open-coded defers and if it finds one, adds a single record to the defer chain | 
 | // for that frame. If sp is non-nil, it starts the stack scan from the frame | 
 | // specified by sp. If sp is nil, it uses the sp from the current defer record | 
 | // (which has just been finished). Hence, it continues the stack scan from the | 
 | // frame of the defer that just finished. It skips any frame that already has an | 
 | // open-coded _defer record, which would have been been created from a previous | 
 | // (unrecovered) panic. | 
 | // | 
 | // Note: All entries of the defer chain (including this new open-coded entry) have | 
 | // their pointers (including sp) adjusted properly if the stack moves while | 
 | // running deferred functions. Also, it is safe to pass in the sp arg (which is | 
 | // the direct result of calling getcallersp()), because all pointer variables | 
 | // (including arguments) are adjusted as needed during stack copies. | 
 | func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) { | 
 | 	var prevDefer *_defer | 
 | 	if sp == nil { | 
 | 		prevDefer = gp._defer | 
 | 		pc = prevDefer.framepc | 
 | 		sp = unsafe.Pointer(prevDefer.sp) | 
 | 	} | 
 | 	systemstack(func() { | 
 | 		gentraceback(pc, uintptr(sp), 0, gp, 0, nil, 0x7fffffff, | 
 | 			func(frame *stkframe, unused unsafe.Pointer) bool { | 
 | 				if prevDefer != nil && prevDefer.sp == frame.sp { | 
 | 					// Skip the frame for the previous defer that | 
 | 					// we just finished (and was used to set | 
 | 					// where we restarted the stack scan) | 
 | 					return true | 
 | 				} | 
 | 				f := frame.fn | 
 | 				fd := funcdata(f, _FUNCDATA_OpenCodedDeferInfo) | 
 | 				if fd == nil { | 
 | 					return true | 
 | 				} | 
 | 				// Insert the open defer record in the | 
 | 				// chain, in order sorted by sp. | 
 | 				d := gp._defer | 
 | 				var prev *_defer | 
 | 				for d != nil { | 
 | 					dsp := d.sp | 
 | 					if frame.sp < dsp { | 
 | 						break | 
 | 					} | 
 | 					if frame.sp == dsp { | 
 | 						if !d.openDefer { | 
 | 							throw("duplicated defer entry") | 
 | 						} | 
 | 						return true | 
 | 					} | 
 | 					prev = d | 
 | 					d = d.link | 
 | 				} | 
 | 				if frame.fn.deferreturn == 0 { | 
 | 					throw("missing deferreturn") | 
 | 				} | 
 |  | 
 | 				maxargsize, _ := readvarintUnsafe(fd) | 
 | 				d1 := newdefer(int32(maxargsize)) | 
 | 				d1.openDefer = true | 
 | 				d1._panic = nil | 
 | 				// These are the pc/sp to set after we've | 
 | 				// run a defer in this frame that did a | 
 | 				// recover. We return to a special | 
 | 				// deferreturn that runs any remaining | 
 | 				// defers and then returns from the | 
 | 				// function. | 
 | 				d1.pc = frame.fn.entry + uintptr(frame.fn.deferreturn) | 
 | 				d1.varp = frame.varp | 
 | 				d1.fd = fd | 
 | 				// Save the SP/PC associated with current frame, | 
 | 				// so we can continue stack trace later if needed. | 
 | 				d1.framepc = frame.pc | 
 | 				d1.sp = frame.sp | 
 | 				d1.link = d | 
 | 				if prev == nil { | 
 | 					gp._defer = d1 | 
 | 				} else { | 
 | 					prev.link = d1 | 
 | 				} | 
 | 				// Stop stack scanning after adding one open defer record | 
 | 				return false | 
 | 			}, | 
 | 			nil, 0) | 
 | 	}) | 
 | } | 
 |  | 
 | // readvarintUnsafe reads the uint32 in varint format starting at fd, and returns the | 
 | // uint32 and a pointer to the byte following the varint. | 
 | // | 
 | // There is a similar function runtime.readvarint, which takes a slice of bytes, | 
 | // rather than an unsafe pointer. These functions are duplicated, because one of | 
 | // the two use cases for the functions would get slower if the functions were | 
 | // combined. | 
 | func readvarintUnsafe(fd unsafe.Pointer) (uint32, unsafe.Pointer) { | 
 | 	var r uint32 | 
 | 	var shift int | 
 | 	for { | 
 | 		b := *(*uint8)((unsafe.Pointer(fd))) | 
 | 		fd = add(fd, unsafe.Sizeof(b)) | 
 | 		if b < 128 { | 
 | 			return r + uint32(b)<<shift, fd | 
 | 		} | 
 | 		r += ((uint32(b) &^ 128) << shift) | 
 | 		shift += 7 | 
 | 		if shift > 28 { | 
 | 			panic("Bad varint") | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // runOpenDeferFrame runs the active open-coded defers in the frame specified by | 
 | // d. It normally processes all active defers in the frame, but stops immediately | 
 | // if a defer does a successful recover. It returns true if there are no | 
 | // remaining defers to run in the frame. | 
 | func runOpenDeferFrame(gp *g, d *_defer) bool { | 
 | 	done := true | 
 | 	fd := d.fd | 
 |  | 
 | 	// Skip the maxargsize | 
 | 	_, fd = readvarintUnsafe(fd) | 
 | 	deferBitsOffset, fd := readvarintUnsafe(fd) | 
 | 	nDefers, fd := readvarintUnsafe(fd) | 
 | 	deferBits := *(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) | 
 |  | 
 | 	for i := int(nDefers) - 1; i >= 0; i-- { | 
 | 		// read the funcdata info for this defer | 
 | 		var argWidth, closureOffset, nArgs uint32 | 
 | 		argWidth, fd = readvarintUnsafe(fd) | 
 | 		closureOffset, fd = readvarintUnsafe(fd) | 
 | 		nArgs, fd = readvarintUnsafe(fd) | 
 | 		if deferBits&(1<<i) == 0 { | 
 | 			for j := uint32(0); j < nArgs; j++ { | 
 | 				_, fd = readvarintUnsafe(fd) | 
 | 				_, fd = readvarintUnsafe(fd) | 
 | 				_, fd = readvarintUnsafe(fd) | 
 | 			} | 
 | 			continue | 
 | 		} | 
 | 		closure := *(**funcval)(unsafe.Pointer(d.varp - uintptr(closureOffset))) | 
 | 		d.fn = closure | 
 | 		deferArgs := deferArgs(d) | 
 | 		// If there is an interface receiver or method receiver, it is | 
 | 		// described/included as the first arg. | 
 | 		for j := uint32(0); j < nArgs; j++ { | 
 | 			var argOffset, argLen, argCallOffset uint32 | 
 | 			argOffset, fd = readvarintUnsafe(fd) | 
 | 			argLen, fd = readvarintUnsafe(fd) | 
 | 			argCallOffset, fd = readvarintUnsafe(fd) | 
 | 			memmove(unsafe.Pointer(uintptr(deferArgs)+uintptr(argCallOffset)), | 
 | 				unsafe.Pointer(d.varp-uintptr(argOffset)), | 
 | 				uintptr(argLen)) | 
 | 		} | 
 | 		deferBits = deferBits &^ (1 << i) | 
 | 		*(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) = deferBits | 
 | 		p := d._panic | 
 | 		reflectcallSave(p, unsafe.Pointer(closure), deferArgs, argWidth) | 
 | 		if p != nil && p.aborted { | 
 | 			break | 
 | 		} | 
 | 		d.fn = nil | 
 | 		// These args are just a copy, so can be cleared immediately | 
 | 		memclrNoHeapPointers(deferArgs, uintptr(argWidth)) | 
 | 		if d._panic != nil && d._panic.recovered { | 
 | 			done = deferBits == 0 | 
 | 			break | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return done | 
 | } | 
 |  | 
 | // reflectcallSave calls reflectcall after saving the caller's pc and sp in the | 
 | // panic record. This allows the runtime to return to the Goexit defer processing | 
 | // loop, in the unusual case where the Goexit may be bypassed by a successful | 
 | // recover. | 
 | func reflectcallSave(p *_panic, fn, arg unsafe.Pointer, argsize uint32) { | 
 | 	if p != nil { | 
 | 		p.argp = unsafe.Pointer(getargp(0)) | 
 | 		p.pc = getcallerpc() | 
 | 		p.sp = unsafe.Pointer(getcallersp()) | 
 | 	} | 
 | 	reflectcall(nil, fn, arg, argsize, argsize) | 
 | 	if p != nil { | 
 | 		p.pc = 0 | 
 | 		p.sp = unsafe.Pointer(nil) | 
 | 	} | 
 | } | 
 |  | 
 | // The implementation of the predeclared function panic. | 
 | func gopanic(e interface{}) { | 
 | 	gp := getg() | 
 | 	if gp.m.curg != gp { | 
 | 		print("panic: ") | 
 | 		printany(e) | 
 | 		print("\n") | 
 | 		throw("panic on system stack") | 
 | 	} | 
 |  | 
 | 	if gp.m.mallocing != 0 { | 
 | 		print("panic: ") | 
 | 		printany(e) | 
 | 		print("\n") | 
 | 		throw("panic during malloc") | 
 | 	} | 
 | 	if gp.m.preemptoff != "" { | 
 | 		print("panic: ") | 
 | 		printany(e) | 
 | 		print("\n") | 
 | 		print("preempt off reason: ") | 
 | 		print(gp.m.preemptoff) | 
 | 		print("\n") | 
 | 		throw("panic during preemptoff") | 
 | 	} | 
 | 	if gp.m.locks != 0 { | 
 | 		print("panic: ") | 
 | 		printany(e) | 
 | 		print("\n") | 
 | 		throw("panic holding locks") | 
 | 	} | 
 |  | 
 | 	var p _panic | 
 | 	p.arg = e | 
 | 	p.link = gp._panic | 
 | 	gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) | 
 |  | 
 | 	atomic.Xadd(&runningPanicDefers, 1) | 
 |  | 
 | 	// By calculating getcallerpc/getcallersp here, we avoid scanning the | 
 | 	// gopanic frame (stack scanning is slow...) | 
 | 	addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp())) | 
 |  | 
 | 	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. An earlier panic will not continue running, but we will make sure below that an | 
 | 		// earlier Goexit does continue running. | 
 | 		if d.started { | 
 | 			if d._panic != nil { | 
 | 				d._panic.aborted = true | 
 | 			} | 
 | 			d._panic = nil | 
 | 			if !d.openDefer { | 
 | 				// For open-coded defers, we need to process the | 
 | 				// defer again, in case there are any other defers | 
 | 				// to call in the frame (not including the defer | 
 | 				// call that caused the panic). | 
 | 				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 happens 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))) | 
 |  | 
 | 		done := true | 
 | 		if d.openDefer { | 
 | 			done = runOpenDeferFrame(gp, d) | 
 | 			if done && !d._panic.recovered { | 
 | 				addOneOpenDeferFrame(gp, 0, nil) | 
 | 			} | 
 | 		} else { | 
 | 			p.argp = unsafe.Pointer(getargp(0)) | 
 | 			reflectcall(nil, 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 { | 
 | 			throw("bad defer entry in panic") | 
 | 		} | 
 | 		d._panic = nil | 
 |  | 
 | 		// trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic | 
 | 		//GC() | 
 |  | 
 | 		pc := d.pc | 
 | 		sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy | 
 | 		if done { | 
 | 			d.fn = nil | 
 | 			gp._defer = d.link | 
 | 			freedefer(d) | 
 | 		} | 
 | 		if p.recovered { | 
 | 			gp._panic = p.link | 
 | 			if gp._panic != nil && gp._panic.goexit && gp._panic.aborted { | 
 | 				// A normal recover would bypass/abort the Goexit.  Instead, | 
 | 				// we return to the processing loop of the Goexit. | 
 | 				gp.sigcode0 = uintptr(gp._panic.sp) | 
 | 				gp.sigcode1 = uintptr(gp._panic.pc) | 
 | 				mcall(recovery) | 
 | 				throw("bypassed recovery failed") // mcall should not return | 
 | 			} | 
 | 			atomic.Xadd(&runningPanicDefers, -1) | 
 |  | 
 | 			if done { | 
 | 				// Remove any remaining non-started, open-coded | 
 | 				// defer entries after a recover, since the | 
 | 				// corresponding defers will be executed normally | 
 | 				// (inline). Any such entry will become stale once | 
 | 				// we run the corresponding defers inline and exit | 
 | 				// the associated stack frame. | 
 | 				d := gp._defer | 
 | 				var prev *_defer | 
 | 				for d != nil { | 
 | 					if d.openDefer { | 
 | 						if d.started { | 
 | 							// This defer is started but we | 
 | 							// are in the middle of a | 
 | 							// defer-panic-recover inside of | 
 | 							// it, so don't remove it or any | 
 | 							// further defer entries | 
 | 							break | 
 | 						} | 
 | 						if prev == nil { | 
 | 							gp._defer = d.link | 
 | 						} else { | 
 | 							prev.link = d.link | 
 | 						} | 
 | 						newd := d.link | 
 | 						freedefer(d) | 
 | 						d = newd | 
 | 					} else { | 
 | 						prev = d | 
 | 						d = d.link | 
 | 					} | 
 | 				} | 
 | 			} | 
 |  | 
 | 			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(sp) | 
 | 			gp.sigcode1 = pc | 
 | 			mcall(recovery) | 
 | 			throw("recovery failed") // mcall should not return | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// ran out of deferred calls - old-school panic now | 
 | 	// Because it is unsafe to call arbitrary user code after freezing | 
 | 	// the world, we call preprintpanics to invoke all necessary Error | 
 | 	// and String methods to prepare the panic strings before startpanic. | 
 | 	preprintpanics(gp._panic) | 
 |  | 
 | 	fatalpanic(gp._panic) // should not return | 
 | 	*(*int)(nil) = 0      // not reached | 
 | } | 
 |  | 
 | // getargp returns the location where the caller | 
 | // writes outgoing function call arguments. | 
 | //go:nosplit | 
 | //go:noinline | 
 | func getargp(x int) uintptr { | 
 | 	// x is an argument mainly so that we can return its address. | 
 | 	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.goexit && !p.recovered && argp == uintptr(p.argp) { | 
 | 		p.recovered = true | 
 | 		return p.arg | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | //go:linkname sync_throw sync.throw | 
 | func sync_throw(s string) { | 
 | 	throw(s) | 
 | } | 
 |  | 
 | //go:nosplit | 
 | func throw(s string) { | 
 | 	// Everything throw does should be recursively nosplit so it | 
 | 	// can be called even when it's unsafe to grow the stack. | 
 | 	systemstack(func() { | 
 | 		print("fatal error: ", s, "\n") | 
 | 	}) | 
 | 	gp := getg() | 
 | 	if gp.m.throwing == 0 { | 
 | 		gp.m.throwing = 1 | 
 | 	} | 
 | 	fatalthrow() | 
 | 	*(*int)(nil) = 0 // not reached | 
 | } | 
 |  | 
 | // runningPanicDefers is non-zero while running deferred functions for panic. | 
 | // runningPanicDefers is incremented and decremented atomically. | 
 | // This is used to try hard to get a panic stack trace out when exiting. | 
 | var runningPanicDefers uint32 | 
 |  | 
 | // panicking is non-zero when crashing the program for an unrecovered panic. | 
 | // panicking is incremented and decremented atomically. | 
 | var panicking uint32 | 
 |  | 
 | // paniclk is held while printing the panic information and stack trace, | 
 | // so that two concurrent panics don't overlap their output. | 
 | var paniclk mutex | 
 |  | 
 | // Unwind the stack after a deferred function calls recover | 
 | // after a panic. Then arrange to continue running as though | 
 | // the caller of the deferred function returned normally. | 
 | func recovery(gp *g) { | 
 | 	// Info about defer passed in G struct. | 
 | 	sp := gp.sigcode0 | 
 | 	pc := gp.sigcode1 | 
 |  | 
 | 	// d's arguments need to be in the stack. | 
 | 	if sp != 0 && (sp < gp.stack.lo || gp.stack.hi < sp) { | 
 | 		print("recover: ", hex(sp), " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n") | 
 | 		throw("bad recovery") | 
 | 	} | 
 |  | 
 | 	// Make the deferproc for this d return again, | 
 | 	// this time returning 1. The calling function will | 
 | 	// jump to the standard return epilogue. | 
 | 	gp.sched.sp = sp | 
 | 	gp.sched.pc = pc | 
 | 	gp.sched.lr = 0 | 
 | 	gp.sched.ret = 1 | 
 | 	gogo(&gp.sched) | 
 | } | 
 |  | 
 | // fatalthrow implements an unrecoverable runtime throw. It freezes the | 
 | // system, prints stack traces starting from its caller, and terminates the | 
 | // process. | 
 | // | 
 | //go:nosplit | 
 | func fatalthrow() { | 
 | 	pc := getcallerpc() | 
 | 	sp := getcallersp() | 
 | 	gp := getg() | 
 | 	// Switch to the system stack to avoid any stack growth, which | 
 | 	// may make things worse if the runtime is in a bad state. | 
 | 	systemstack(func() { | 
 | 		startpanic_m() | 
 |  | 
 | 		if dopanic_m(gp, pc, sp) { | 
 | 			// crash uses a decent amount of nosplit stack and we're already | 
 | 			// low on stack in throw, so crash on the system stack (unlike | 
 | 			// fatalpanic). | 
 | 			crash() | 
 | 		} | 
 |  | 
 | 		exit(2) | 
 | 	}) | 
 |  | 
 | 	*(*int)(nil) = 0 // not reached | 
 | } | 
 |  | 
 | // fatalpanic implements an unrecoverable panic. It is like fatalthrow, except | 
 | // that if msgs != nil, fatalpanic also prints panic messages and decrements | 
 | // runningPanicDefers once main is blocked from exiting. | 
 | // | 
 | //go:nosplit | 
 | func fatalpanic(msgs *_panic) { | 
 | 	pc := getcallerpc() | 
 | 	sp := getcallersp() | 
 | 	gp := getg() | 
 | 	var docrash bool | 
 | 	// Switch to the system stack to avoid any stack growth, which | 
 | 	// may make things worse if the runtime is in a bad state. | 
 | 	systemstack(func() { | 
 | 		if startpanic_m() && msgs != nil { | 
 | 			// There were panic messages and startpanic_m | 
 | 			// says it's okay to try to print them. | 
 |  | 
 | 			// startpanic_m set panicking, which will | 
 | 			// block main from exiting, so now OK to | 
 | 			// decrement runningPanicDefers. | 
 | 			atomic.Xadd(&runningPanicDefers, -1) | 
 |  | 
 | 			printpanics(msgs) | 
 | 		} | 
 |  | 
 | 		docrash = dopanic_m(gp, pc, sp) | 
 | 	}) | 
 |  | 
 | 	if docrash { | 
 | 		// By crashing outside the above systemstack call, debuggers | 
 | 		// will not be confused when generating a backtrace. | 
 | 		// Function crash is marked nosplit to avoid stack growth. | 
 | 		crash() | 
 | 	} | 
 |  | 
 | 	systemstack(func() { | 
 | 		exit(2) | 
 | 	}) | 
 |  | 
 | 	*(*int)(nil) = 0 // not reached | 
 | } | 
 |  | 
 | // startpanic_m prepares for an unrecoverable panic. | 
 | // | 
 | // It returns true if panic messages should be printed, or false if | 
 | // the runtime is in bad shape and should just print stacks. | 
 | // | 
 | // It must not have write barriers even though the write barrier | 
 | // explicitly ignores writes once dying > 0. Write barriers still | 
 | // assume that g.m.p != nil, and this function may not have P | 
 | // in some contexts (e.g. a panic in a signal handler for a signal | 
 | // sent to an M with no P). | 
 | // | 
 | //go:nowritebarrierrec | 
 | func startpanic_m() bool { | 
 | 	_g_ := getg() | 
 | 	if mheap_.cachealloc.size == 0 { // very early | 
 | 		print("runtime: panic before malloc heap initialized\n") | 
 | 	} | 
 | 	// Disallow malloc during an unrecoverable panic. A panic | 
 | 	// could happen in a signal handler, or in a throw, or inside | 
 | 	// malloc itself. We want to catch if an allocation ever does | 
 | 	// happen (even if we're not in one of these situations). | 
 | 	_g_.m.mallocing++ | 
 |  | 
 | 	// If we're dying because of a bad lock count, set it to a | 
 | 	// good lock count so we don't recursively panic below. | 
 | 	if _g_.m.locks < 0 { | 
 | 		_g_.m.locks = 1 | 
 | 	} | 
 |  | 
 | 	switch _g_.m.dying { | 
 | 	case 0: | 
 | 		// Setting dying >0 has the side-effect of disabling this G's writebuf. | 
 | 		_g_.m.dying = 1 | 
 | 		atomic.Xadd(&panicking, 1) | 
 | 		lock(&paniclk) | 
 | 		if debug.schedtrace > 0 || debug.scheddetail > 0 { | 
 | 			schedtrace(true) | 
 | 		} | 
 | 		freezetheworld() | 
 | 		return true | 
 | 	case 1: | 
 | 		// Something failed while panicking. | 
 | 		// Just print a stack trace and exit. | 
 | 		_g_.m.dying = 2 | 
 | 		print("panic during panic\n") | 
 | 		return false | 
 | 	case 2: | 
 | 		// This is a genuine bug in the runtime, we couldn't even | 
 | 		// print the stack trace successfully. | 
 | 		_g_.m.dying = 3 | 
 | 		print("stack trace unavailable\n") | 
 | 		exit(4) | 
 | 		fallthrough | 
 | 	default: | 
 | 		// Can't even print! Just exit. | 
 | 		exit(5) | 
 | 		return false // Need to return something. | 
 | 	} | 
 | } | 
 |  | 
 | var didothers bool | 
 | var deadlock mutex | 
 |  | 
 | func dopanic_m(gp *g, pc, sp uintptr) bool { | 
 | 	if gp.sig != 0 { | 
 | 		signame := signame(gp.sig) | 
 | 		if signame != "" { | 
 | 			print("[signal ", signame) | 
 | 		} else { | 
 | 			print("[signal ", hex(gp.sig)) | 
 | 		} | 
 | 		print(" code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n") | 
 | 	} | 
 |  | 
 | 	level, all, docrash := gotraceback() | 
 | 	_g_ := getg() | 
 | 	if level > 0 { | 
 | 		if gp != gp.m.curg { | 
 | 			all = true | 
 | 		} | 
 | 		if gp != gp.m.g0 { | 
 | 			print("\n") | 
 | 			goroutineheader(gp) | 
 | 			traceback(pc, sp, 0, gp) | 
 | 		} else if level >= 2 || _g_.m.throwing > 0 { | 
 | 			print("\nruntime stack:\n") | 
 | 			traceback(pc, sp, 0, gp) | 
 | 		} | 
 | 		if !didothers && all { | 
 | 			didothers = true | 
 | 			tracebackothers(gp) | 
 | 		} | 
 | 	} | 
 | 	unlock(&paniclk) | 
 |  | 
 | 	if atomic.Xadd(&panicking, -1) != 0 { | 
 | 		// Some other m is panicking too. | 
 | 		// Let it print what it needs to print. | 
 | 		// Wait forever without chewing up cpu. | 
 | 		// It will exit when it's done. | 
 | 		lock(&deadlock) | 
 | 		lock(&deadlock) | 
 | 	} | 
 |  | 
 | 	printDebugLog() | 
 |  | 
 | 	return docrash | 
 | } | 
 |  | 
 | // canpanic returns false if a signal should throw instead of | 
 | // panicking. | 
 | // | 
 | //go:nosplit | 
 | func canpanic(gp *g) bool { | 
 | 	// Note that g is m->gsignal, different from gp. | 
 | 	// Note also that g->m can change at preemption, so m can go stale | 
 | 	// if this function ever makes a function call. | 
 | 	_g_ := getg() | 
 | 	_m_ := _g_.m | 
 |  | 
 | 	// Is it okay for gp to panic instead of crashing the program? | 
 | 	// Yes, as long as it is running Go code, not runtime code, | 
 | 	// and not stuck in a system call. | 
 | 	if gp == nil || gp != _m_.curg { | 
 | 		return false | 
 | 	} | 
 | 	if _m_.locks != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 { | 
 | 		return false | 
 | 	} | 
 | 	status := readgstatus(gp) | 
 | 	if status&^_Gscan != _Grunning || gp.syscallsp != 0 { | 
 | 		return false | 
 | 	} | 
 | 	if GOOS == "windows" && _m_.libcallsp != 0 { | 
 | 		return false | 
 | 	} | 
 | 	return true | 
 | } | 
 |  | 
 | // shouldPushSigpanic reports whether pc should be used as sigpanic's | 
 | // return PC (pushing a frame for the call). Otherwise, it should be | 
 | // left alone so that LR is used as sigpanic's return PC, effectively | 
 | // replacing the top-most frame with sigpanic. This is used by | 
 | // preparePanic. | 
 | func shouldPushSigpanic(gp *g, pc, lr uintptr) bool { | 
 | 	if pc == 0 { | 
 | 		// Probably a call to a nil func. The old LR is more | 
 | 		// useful in the stack trace. Not pushing the frame | 
 | 		// will make the trace look like a call to sigpanic | 
 | 		// instead. (Otherwise the trace will end at sigpanic | 
 | 		// and we won't get to see who faulted.) | 
 | 		return false | 
 | 	} | 
 | 	// If we don't recognize the PC as code, but we do recognize | 
 | 	// the link register as code, then this assumes the panic was | 
 | 	// caused by a call to non-code. In this case, we want to | 
 | 	// ignore this call to make unwinding show the context. | 
 | 	// | 
 | 	// If we running C code, we're not going to recognize pc as a | 
 | 	// Go function, so just assume it's good. Otherwise, traceback | 
 | 	// may try to read a stale LR that looks like a Go code | 
 | 	// pointer and wander into the woods. | 
 | 	if gp.m.incgo || findfunc(pc).valid() { | 
 | 		// This wasn't a bad call, so use PC as sigpanic's | 
 | 		// return PC. | 
 | 		return true | 
 | 	} | 
 | 	if findfunc(lr).valid() { | 
 | 		// This was a bad call, but the LR is good, so use the | 
 | 		// LR as sigpanic's return PC. | 
 | 		return false | 
 | 	} | 
 | 	// Neither the PC or LR is good. Hopefully pushing a frame | 
 | 	// will work. | 
 | 	return true | 
 | } | 
 |  | 
 | // isAbortPC reports whether pc is the program counter at which | 
 | // runtime.abort raises a signal. | 
 | // | 
 | // It is nosplit because it's part of the isgoexception | 
 | // implementation. | 
 | // | 
 | //go:nosplit | 
 | func isAbortPC(pc uintptr) bool { | 
 | 	return pc == funcPC(abort) || ((GOARCH == "arm" || GOARCH == "arm64") && pc == funcPC(abort)+sys.PCQuantum) | 
 | } |