1
0
mirror of https://github.com/golang/go synced 2024-11-19 16:14:49 -07:00

runtime: merge panic1.go back into panic.go

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/139370043
This commit is contained in:
Keith Randall 2014-09-08 12:33:08 -07:00
parent c81a0ed3c5
commit 3a3d47db37
2 changed files with 202 additions and 209 deletions

View File

@ -234,3 +234,205 @@ func 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")
}
var p _panic
var dabort _defer
p.arg = e
p.link = gp._panic
gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
fn := abortpanic
dabort.fn = *(**funcval)(unsafe.Pointer(&fn))
dabort.siz = ptrSize
dabort.args[0] = noescape((unsafe.Pointer)(&p)) // TODO(khr): why do I need noescape here?
dabort.argp = _NoArgs
dabort.special = true
for {
d := gp._defer
if d == nil {
break
}
// take defer off list in case of recursive panic
gp._defer = d.link
argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy
pc := d.pc
// The deferred function may cause another panic,
// so reflectcall may not return. Set up a defer
// to mark this panic aborted if that happens.
dabort.link = gp._defer
gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort)))
p._defer = d
p.argp = getargp(0)
reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz))
p.argp = 0
// reflectcall did not panic. Remove dabort.
if gp._defer != &dabort {
gothrow("bad defer entry in panic")
}
gp._defer = dabort.link
// trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
//GC()
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 and free the associated defers.
for gp._panic != nil && gp._panic.aborted {
freedefer(gp._panic._defer)
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)))
}
func abortpanic(p *_panic) {
p.aborted = true
}
// 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 == p.argp {
p.recovered = true
return p.arg
}
return nil
}
//go:nosplit
func startpanic() {
onM(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(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
}
func panicstring(s *int8) {
// m.softfloat is set during software floating point,
// which might cause a fault during a memory load.
// It increments m.locks to avoid preemption.
// If we're panicking, the software floating point frames
// will be unwound, so decrement m.locks as they would.
gp := getg()
if gp.m.softfloat != 0 {
gp.m.locks--
gp.m.softfloat = 0
}
if gp.m.mallocing != 0 {
print("panic: ", s, "\n")
gothrow("panic during malloc")
}
if gp.m.gcing != 0 {
print("panic: ", s, "\n")
gothrow("panic during gc")
}
if gp.m.locks != 0 {
print("panic: ", s, "\n")
gothrow("panic holding locks")
}
var err interface{}
newErrorCString(unsafe.Pointer(s), &err)
gopanic(err)
}

View File

@ -1,209 +0,0 @@
// Copyright 2012 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"
// 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")
}
var p _panic
var dabort _defer
p.arg = e
p.link = gp._panic
gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
fn := abortpanic
dabort.fn = *(**funcval)(unsafe.Pointer(&fn))
dabort.siz = ptrSize
dabort.args[0] = noescape((unsafe.Pointer)(&p)) // TODO(khr): why do I need noescape here?
dabort.argp = _NoArgs
dabort.special = true
for {
d := gp._defer
if d == nil {
break
}
// take defer off list in case of recursive panic
gp._defer = d.link
argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy
pc := d.pc
// The deferred function may cause another panic,
// so reflectcall may not return. Set up a defer
// to mark this panic aborted if that happens.
dabort.link = gp._defer
gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort)))
p._defer = d
p.argp = getargp(0)
reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz))
p.argp = 0
// reflectcall did not panic. Remove dabort.
if gp._defer != &dabort {
gothrow("bad defer entry in panic")
}
gp._defer = dabort.link
// trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
//GC()
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 and free the associated defers.
for gp._panic != nil && gp._panic.aborted {
freedefer(gp._panic._defer)
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)))
}
func abortpanic(p *_panic) {
p.aborted = true
}
// 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 == p.argp {
p.recovered = true
return p.arg
}
return nil
}
//go:nosplit
func startpanic() {
onM(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(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
}
func panicstring(s *int8) {
// m.softfloat is set during software floating point,
// which might cause a fault during a memory load.
// It increments m.locks to avoid preemption.
// If we're panicking, the software floating point frames
// will be unwound, so decrement m.locks as they would.
gp := getg()
if gp.m.softfloat != 0 {
gp.m.locks--
gp.m.softfloat = 0
}
if gp.m.mallocing != 0 {
print("panic: ", s, "\n")
gothrow("panic during malloc")
}
if gp.m.gcing != 0 {
print("panic: ", s, "\n")
gothrow("panic during gc")
}
if gp.m.locks != 0 {
print("panic: ", s, "\n")
gothrow("panic holding locks")
}
var err interface{}
newErrorCString(unsafe.Pointer(s), &err)
gopanic(err)
}