]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: deferproc/deferreturn in Go
authorKeith Randall <khr@golang.org>
Wed, 3 Sep 2014 15:49:43 +0000 (08:49 -0700)
committerKeith Randall <khr@golang.org>
Wed, 3 Sep 2014 15:49:43 +0000 (08:49 -0700)
LGTM=rsc
R=golang-codereviews, rsc, khr
CC=golang-codereviews
https://golang.org/cl/139900043

13 files changed:
src/cmd/api/goapi.go
src/pkg/runtime/asm_386.s
src/pkg/runtime/asm_amd64.s
src/pkg/runtime/asm_amd64p32.s
src/pkg/runtime/asm_arm.s
src/pkg/runtime/extern.go
src/pkg/runtime/malloc.c
src/pkg/runtime/malloc.h
src/pkg/runtime/panic.c
src/pkg/runtime/panic.go
src/pkg/runtime/stubs.go
src/pkg/runtime/traceback.go
src/pkg/runtime/vlrt.go

index 7f7b389be3215f5c83fefe030cb4b3f731644ba3..ce806fc95d9612a0b22940ad18b81712eddbabfb 100644 (file)
@@ -379,7 +379,9 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
        if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) {
                // Just enough to keep the api checker happy.
                src := "package runtime; type (" +
+                       " _defer struct{};" +
                        " _func struct{};" +
+                       " _select struct{}; " +
                        " _type struct{};" +
                        " alg struct{};" +
                        " chantype struct{};" +
@@ -403,7 +405,6 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
                        " sudog struct{};" +
                        " waitq struct{};" +
                        " wincallbackcontext struct{};" +
-                       " _select struct{}; " +
                        "); " +
                        "const (" +
                        " cb_max = 2000;" +
index 8a5fd3fb0846754de378c878009ebff040af3333..2477726f5139ad001a89531d617376d569146ff9 100644 (file)
@@ -2310,3 +2310,7 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
        MOVL    DX, m_fastrand(AX)
        MOVL    DX, ret+0(FP)
        RET
+
+TEXT runtime·return0(SB), NOSPLIT, $0
+       MOVL    $0, AX
+       RET
index 0846966f123fee93ee7906bb1829598bf2f8cf44..d7e30de7b4696323ee8b534777e4a3a7bc594811 100644 (file)
@@ -2362,3 +2362,7 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
        MOVL    DX, m_fastrand(AX)
        MOVL    DX, ret+0(FP)
        RET
+
+TEXT runtime·return0(SB), NOSPLIT, $0
+       MOVL    $0, AX
+       RET
index 7886861eb228b7a784af7ca987f2ac3f2cf8cbe8..5ff89cf068dd1893879ebcd5112d1319fb1fa237 100644 (file)
@@ -1232,3 +1232,7 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
        MOVL    DX, m_fastrand(AX)
        MOVL    DX, ret+0(FP)
        RET
+
+TEXT runtime·return0(SB), NOSPLIT, $0
+       MOVL    $0, AX
+       RET
index 67763e1b2e8e853791473e9541df61a60eab76c1..26b58cfb17a8c641a7fe402b412b259ac4a46936 100644 (file)
@@ -1286,3 +1286,6 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $-4-4
 TEXT runtime·gocputicks(SB), NOSPLIT, $0
        B runtime·cputicks(SB)
 
+TEXT runtime·return0(SB), NOSPLIT, $0
+       MOVW    $0, R0
+       RET
index d75d2b4e544cc15fe3f2759302ce5ece8b4b4ef0..2ca22d923bcab9549bb226803c79e114af618f13 100644 (file)
@@ -77,15 +77,6 @@ package runtime
 
 import "unsafe"
 
-// 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()
-
 // sigpanic is the C function sigpanic.
 // That is, unsafe.Pointer(&sigpanic) is the C function pointer for sigpanic.
 var sigpanic struct{}
index 8210081553619f140902a1fbe1a9d3234cfade2d..311cc442c20e2b7459fe86b42f64a9778d5addcf 100644 (file)
@@ -21,7 +21,7 @@ MHeap runtime·mheap;
 #pragma dataflag NOPTR
 MStats runtime·memstats;
 
-static Type* notype;
+Type* runtime·conservative;
 
 void runtime·cmallocgc(uintptr size, Type *typ, uint32 flag, void **ret);
 void runtime·gc_notype_ptr(Eface*);
@@ -35,7 +35,7 @@ runtime·mallocgc(uintptr size, Type *typ, uint32 flag)
        // TODO: maybe someday we can get rid of this.  It is
        // probably the only location where we run Go code on the M stack.
        if((flag&FlagNoScan) == 0 && typ == nil)
-               typ = notype;
+               typ = runtime·conservative;
        runtime·cmallocgc(size, typ, flag, &ret);
        return ret;
 }
@@ -259,7 +259,7 @@ runtime·mallocinit(void)
        g->m->mcache = runtime·allocmcache();
 
        runtime·gc_notype_ptr(&notype_eface);
-       notype = notype_eface.type;
+       runtime·conservative = notype_eface.type;
 }
 
 void*
index f328feb1728d5536dcddb1efd12e9d1a43787c86..d9a2bf84bad4bf8129e6e9c728c91aeb30b70492 100644 (file)
@@ -528,6 +528,7 @@ void*       runtime·cnewarray(Type*, intgo);
 void   runtime·tracealloc(void*, uintptr, Type*);
 void   runtime·tracefree(void*, uintptr);
 void   runtime·tracegc(void);
+extern Type*   runtime·conservative;
 
 int32  runtime·gcpercent;
 int32  runtime·readgogc(void);
index 4b6829e011025cb41568ef75637125819fd76e74..72078f43435a6e266ef68062171c36d12a658962 100644 (file)
 
 // Code related to defer, panic and recover.
 
+// TODO: remove once code is moved to Go
+extern Defer* runtime·newdefer(int32 siz);
+extern runtime·freedefer(Defer *d);
+
 uint32 runtime·panicking;
 static Mutex paniclk;
 
-// 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
-#define DEFERCLASS(sz) (((sz)+7)>>4)
-// total size of memory block for defer with arg size sz
-#define TOTALSIZE(sz) (sizeof(Defer) - sizeof(((Defer*)nil)->args) + ROUND(sz, sizeof(uintptr)))
-
-// Allocate a Defer, usually using per-P pool.
-// Each defer must be released with freedefer.
-static Defer*
-newdefer(int32 siz)
-{
-       int32 total, sc;
-       Defer *d;
-       P *p;
-
-       d = nil;
-       sc = DEFERCLASS(siz);
-       if(sc < nelem(p->deferpool)) {
-               p = g->m->p;
-               d = p->deferpool[sc];
-               if(d)
-                       p->deferpool[sc] = d->link;
-       }
-       if(d == nil) {
-               // deferpool is empty or just a big defer
-               total = runtime·roundupsize(TOTALSIZE(siz));
-               d = runtime·mallocgc(total, nil, 0);
-       }
-       d->siz = siz;
-       d->special = 0;
-       d->link = g->defer;
-       g->defer = d;
-       return d;
-}
-
-// Free the given defer.
-// The defer cannot be used after this call.
-static void
-freedefer(Defer *d)
-{
-       int32 sc;
-       P *p;
-
-       if(d->special)
-               return;
-       sc = DEFERCLASS(d->siz);
-       if(sc < nelem(p->deferpool)) {
-               p = g->m->p;
-               d->link = p->deferpool[sc];
-               p->deferpool[sc] = d;
-               // No need to wipe out pointers in argp/pc/fn/args,
-               // because we empty the pool before GC.
-       }
-}
-
-// Create a new deferred function fn with siz bytes of arguments.
-// The compiler turns a defer statement into a call to this.
-// Cannot split the stack because it assumes that the arguments
-// are available sequentially after &fn; they would not be
-// copied if a stack split occurred.  It's OK for this to call
-// functions that split the stack.
-#pragma textflag NOSPLIT
-uintptr
-runtime·deferproc(int32 siz, FuncVal *fn, ...)
-{
-       Defer *d;
-
-       d = newdefer(siz);
-       d->fn = fn;
-       d->pc = (uintptr)runtime·getcallerpc(&siz);
-       if(thechar == '5')
-               d->argp = (uintptr)(&fn+2);  // skip caller's saved link register
-       else
-               d->argp = (uintptr)(&fn+1);
-       runtime·memmove(d->args, (byte*)d->argp, d->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.
-       return 0;
-}
-
-// 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.
-#pragma textflag NOSPLIT
 void
-runtime·deferreturn(uintptr arg0)
-{
-       Defer *d;
-       uintptr argp;
+runtime·deferproc_m(void) {
+       int32 siz;
        FuncVal *fn;
-
-       d = g->defer;
-       if(d == nil)
-               return;
-       argp = (uintptr)&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.
-       g->m->locks++;
-       runtime·memmove((byte*)argp, d->args, d->siz);
-       fn = d->fn;
-       g->defer = d->link;
-       freedefer(d);
-       g->m->locks--;
-       if(g->m->locks == 0 && g->preempt)
-               g->stackguard0 = StackPreempt;
-       runtime·jmpdefer(fn, argp);
-}
-
-// Ensure that defer arg sizes that map to the same defer size class
-// also map to the same malloc size class.
-void
-runtime·testdefersizes(void)
-{
-       P *p;
-       int32 i, siz, defersc, mallocsc;
-       int32 map[nelem(p->deferpool)];
-
-       for(i=0; i<nelem(p->deferpool); i++)
-               map[i] = -1;
-       for(i=0;; i++) {
-               defersc = DEFERCLASS(i);
-               if(defersc >= nelem(p->deferpool))
-                       break;
-               siz = TOTALSIZE(i);
-               mallocsc = runtime·SizeToClass(siz);
-               siz = runtime·class_to_size[mallocsc];
-               // runtime·printf("defer class %d: arg size %d, block size %d(%d)\n", defersc, i, siz, mallocsc);
-               if(map[defersc] < 0) {
-                       map[defersc] = mallocsc;
-                       continue;
-               }
-               if(map[defersc] != mallocsc) {
-                       runtime·printf("bad defer size class: i=%d siz=%d mallocsc=%d/%d\n",
-                               i, siz, map[defersc], mallocsc);
-                       runtime·throw("bad defer size class");
-               }
-       }
-}
-
-// Run all deferred functions for the current goroutine.
-static void
-rundefer(void)
-{
+       uintptr argp;
+       uintptr callerpc;
        Defer *d;
 
-       while((d = g->defer) != nil) {
-               g->defer = d->link;
-               reflect·call(d->fn, (byte*)d->args, d->siz, d->siz);
-               freedefer(d);
-       }
+       siz = g->m->scalararg[0];
+       fn = g->m->ptrarg[0];
+       argp = g->m->scalararg[1];
+       callerpc = g->m->scalararg[2];
+       g->m->ptrarg[0] = nil;
+
+       d = runtime·newdefer(siz);
+       d->fn = fn;
+       d->pc = callerpc;
+       d->argp = argp;
+       runtime·memmove(d->args, (void*)argp, siz);
 }
 
 // Print all currently active panics.  Used when crashing.
@@ -252,14 +102,14 @@ runtime·panic(Eface e)
                        runtime·throw("bad defer entry in panic");
                g->defer = dabort.link;
 
-               freedefer(d);
+               runtime·freedefer(d);
                if(p.recovered) {
                        g->panic = p.link;
                        // Aborted panics are marked but remain on the g->panic list.
                        // Recovery will unwind the stack frames containing their Panic structs.
                        // Remove them from the list and free the associated defers.
                        while(g->panic && g->panic->aborted) {
-                               freedefer(g->panic->defer);
+                               runtime·freedefer(g->panic->defer);
                                g->panic = g->panic->link;
                        }
                        if(g->panic == nil)     // must be done with signal
@@ -464,20 +314,6 @@ runtime·dopanic(int32 unused)
        runtime·exit(2);
 }
 
-void
-runtime·throwreturn(void)
-{
-       // can only happen if compiler is broken
-       runtime·throw("no return at end of a typed function - compiler is broken");
-}
-
-void
-runtime·throwinit(void)
-{
-       // can only happen with linker skew
-       runtime·throw("recursive call during initialization - linker skew");
-}
-
 bool
 runtime·canpanic(G *gp)
 {
@@ -560,16 +396,3 @@ runtime·panicstring(int8 *s)
        runtime·newErrorCString(s, &err);
        runtime·panic(err);
 }
-
-void
-runtime·Goexit(void)
-{
-       rundefer();
-       runtime·goexit();
-}
-
-void
-runtime·panicdivide(void)
-{
-       runtime·panicstring("integer divide by zero");
-}
index 9b95f496737203ddbbdf5d74c222171e8dc28485..1e35561d1541af81e92c88958b699db17e3c0a55 100644 (file)
@@ -4,6 +4,8 @@
 
 package runtime
 
+import "unsafe"
+
 var indexError = error(errorString("index out of range"))
 
 func panicindex() {
@@ -15,3 +17,200 @@ 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()
+}
index b002da98b423f1fa60f90d5001dd57ca694ad66f..bf83500b5a2f33822d4cfc056cd43486a3a30ec0 100644 (file)
@@ -41,6 +41,7 @@ func racereleaseg(gp *g, addr unsafe.Pointer)
 func racefingo()
 
 // Should be a built-in for unsafe.Pointer?
+//go:nosplit
 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
        return unsafe.Pointer(uintptr(p) + x)
 }
@@ -85,6 +86,8 @@ func unrollgcproginplace_m()
 func setgcpercent_m()
 func setmaxthreads_m()
 func ready_m()
+func deferproc_m()
+func goexit_m()
 
 // memclr clears n bytes starting at ptr.
 // in memclr_*.s
@@ -126,6 +129,7 @@ func gothrow(s string)
 // output depends on the input.  noescape is inlined and currently
 // compiles down to a single xor instruction.
 // USE CAREFULLY!
+//go:nosplit
 func noescape(p unsafe.Pointer) unsafe.Pointer {
        x := uintptr(p)
        return unsafe.Pointer(x ^ 0)
@@ -141,7 +145,9 @@ func gosave(buf *gobuf)
 func read(fd int32, p unsafe.Pointer, n int32) int32
 func close(fd int32) int32
 func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
-func jmpdefer(fv *funcval, argp unsafe.Pointer)
+
+//go:noescape
+func jmpdefer(fv *funcval, argp uintptr)
 func exit1(code int32)
 func asminit()
 func setg(gg *g)
@@ -162,6 +168,7 @@ func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer
 func readgogc() int32
 func purgecachedstats(c *mcache)
 func gostringnocopy(b *byte) string
+func goexit()
 
 //go:noescape
 func write(fd uintptr, p unsafe.Pointer, n int32) int32
@@ -249,8 +256,15 @@ func gofuncname(f *_func) string {
 
 const _NoArgs = ^uintptr(0)
 
-var newproc, deferproc, lessstack struct{} // C/assembly functions
+var newproc, lessstack struct{} // C/assembly functions
 
 func funcspdelta(*_func, uintptr) int32 // symtab.c
 func funcarglen(*_func, uintptr) int32  // symtab.c
 const _ArgsSizeUnknown = -0x80000000    // funcdata.h
+
+// return0 is a stub used to return 0 from deferproc.
+// It is called at the very end of deferproc to signal
+// the calling Go function that it should not jump
+// to deferreturn.
+// in asm_*.s
+func return0()
index 26d0f5fc92caab0b5882e728dbf51e4695aebd72..6286c9dac151a1c5e6ecf7779f5f03bf3dacc00f 100644 (file)
@@ -33,6 +33,7 @@ const usesLR = GOARCH != "amd64" && GOARCH != "amd64p32" && GOARCH != "386"
 // jmpdeferPC is the PC at the beginning of the jmpdefer assembly function.
 // The traceback needs to recognize it on link register architectures.
 var jmpdeferPC = funcPC(jmpdefer)
+var deferprocPC = funcPC(deferproc)
 
 // System-specific hook. See traceback_windows.go
 var systraceback func(*_func, *stkframe, *g, bool, func(*stkframe, unsafe.Pointer) bool, unsafe.Pointer) (changed, aborted bool)
@@ -342,7 +343,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 
        skipped:
                waspanic = f.entry == uintptr(unsafe.Pointer(&sigpanic))
-               wasnewproc = f.entry == uintptr(unsafe.Pointer(&newproc)) || f.entry == uintptr(unsafe.Pointer(&deferproc))
+               wasnewproc = f.entry == uintptr(unsafe.Pointer(&newproc)) || f.entry == deferprocPC
 
                // Do not unwind past the bottom of the stack.
                if flr == nil {
@@ -582,7 +583,6 @@ func tracebackothers(me *g) {
        unlock(&allglock)
 }
 
-func goexit()
 func mstart()
 func morestack()
 func rt0_go()
index 50097edde769baa31cf326457f5dab1caca2a119..6370732ca0d387effbb9ff0ac0ca9ba6a1ece624 100644 (file)
@@ -256,5 +256,3 @@ func slowdodiv(n, d uint64) (q, r uint64) {
        }
        return q, n
 }
-
-func panicdivide()