diff options
| author | Russ Cox <rsc@golang.org> | 2014-09-05 16:51:45 -0400 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2014-09-05 16:51:45 -0400 |
| commit | f8f630f5ecb5e30c9feadab5277f393c58da71f6 (patch) | |
| tree | aa4b7ec09ae38d6fff0c7c0e9e85cccfc6b5a96c /src/pkg/runtime/stack.c | |
| parent | fcbe51c9e3ecbb1cb5d8d50f64b0bc42a6a0c7f5 (diff) | |
| download | go-f8f630f5ecb5e30c9feadab5277f393c58da71f6.tar.xz | |
runtime: use reflect.call during panic instead of newstackcall
newstackcall creates a new stack segment, and we want to
be able to throw away all that code.
LGTM=khr
R=khr, iant
CC=dvyukov, golang-codereviews, r
https://golang.org/cl/139270043
Diffstat (limited to 'src/pkg/runtime/stack.c')
| -rw-r--r-- | src/pkg/runtime/stack.c | 92 |
1 files changed, 39 insertions, 53 deletions
diff --git a/src/pkg/runtime/stack.c b/src/pkg/runtime/stack.c index f0861e4085..facf0c5e82 100644 --- a/src/pkg/runtime/stack.c +++ b/src/pkg/runtime/stack.c @@ -25,6 +25,8 @@ enum StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use after free StackCache = 1, + + StackCopyAlways = 1, // expect to be able to copy stacks 100% of the time }; // Global pool of spans that have free stacks. @@ -324,6 +326,9 @@ runtime·oldstack(void) int64 goid; int32 oldstatus; + if(StackCopyAlways) + runtime·throw("unexpected call to oldstack"); + gp = g->m->curg; top = (Stktop*)gp->stackbase; if(top == nil) @@ -442,14 +447,14 @@ checkframecopy(Stkframe *frame, void *arg) stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); if(stackmap == nil) { cinfo->frames = -1; - if(StackDebug >= 1) - runtime·printf("copystack: no locals info for %s\n", runtime·funcname(f)); + if(StackDebug >= 1 || StackCopyAlways) + runtime·printf("runtime: copystack: no locals info for %s\n", runtime·funcname(f)); return false; } if(stackmap->n <= 0) { cinfo->frames = -1; - if(StackDebug >= 1) - runtime·printf("copystack: locals size info only for %s\n", runtime·funcname(f)); + if(StackDebug >= 1 || StackCopyAlways) + runtime·printf("runtime: copystack: locals size info only for %s\n", runtime·funcname(f)); return false; } } @@ -457,8 +462,8 @@ checkframecopy(Stkframe *frame, void *arg) stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); if(stackmap == nil) { cinfo->frames = -1; - if(StackDebug >= 1) - runtime·printf("copystack: no arg info for %s\n", runtime·funcname(f)); + if(StackDebug >= 1 || StackCopyAlways) + runtime·printf("runtime: copystack: no arg info for %s\n", runtime·funcname(f)); return false; } } @@ -510,8 +515,8 @@ copyabletopsegment(G *gp) continue; f = runtime·findfunc((uintptr)fn->fn); if(f == nil) { - if(StackDebug >= 1) - runtime·printf("copystack: no func for deferred pc %p\n", fn->fn); + if(StackDebug >= 1 || StackCopyAlways) + runtime·printf("runtime: copystack: no func for deferred pc %p\n", fn->fn); return -1; } @@ -522,14 +527,14 @@ copyabletopsegment(G *gp) // C (particularly, cgo) lies to us. See issue 7695. stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); if(stackmap == nil || stackmap->n <= 0) { - if(StackDebug >= 1) - runtime·printf("copystack: no arg info for deferred %s\n", runtime·funcname(f)); + if(StackDebug >= 1 || StackCopyAlways) + runtime·printf("runtime: copystack: no arg info for deferred %s\n", runtime·funcname(f)); return -1; } stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); if(stackmap == nil || stackmap->n <= 0) { - if(StackDebug >= 1) - runtime·printf("copystack: no local info for deferred %s\n", runtime·funcname(f)); + if(StackDebug >= 1 || StackCopyAlways) + runtime·printf("runtime: copystack: no local info for deferred %s\n", runtime·funcname(f)); return -1; } @@ -755,20 +760,17 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) static void adjustpanics(G *gp, AdjustInfo *adjinfo) { - Panic *p; + Panic *p, **l; // only the topmost panic is on the current stack - p = gp->panic; - if(p == nil) - return; - if(p->link != nil) { - // only the topmost panic can be on the current stack - // (because panic runs defers on a new stack) - if(adjinfo->oldstk <= (byte*)p->link && (byte*)p->link < adjinfo->oldbase) - runtime·throw("two panics on one stack"); + for(l = &gp->panic; (p = *l) != nil; ) { + if(adjinfo->oldstk <= (byte*)p && (byte*)p < adjinfo->oldbase) + *l = (Panic*)((byte*)p + adjinfo->delta); + l = &p->link; + + if(adjinfo->oldstk <= (byte*)p->argp && (byte*)p->argp < adjinfo->oldbase) + p->argp += adjinfo->delta; } - if(adjinfo->oldstk <= (byte*)p && (byte*)p < adjinfo->oldbase) - gp->panic = (Panic*)((byte*)p + adjinfo->delta); } static void @@ -867,11 +869,10 @@ runtime·round2(int32 x) return 1 << s; } -// Called from runtime·newstackcall or from runtime·morestack when a new -// stack segment is needed. Allocate a new stack big enough for -// m->moreframesize bytes, copy m->moreargsize bytes to the new frame, -// and then act as though runtime·lessstack called the function at -// m->morepc. +// Called from runtime·morestack when a new stack segment is needed. +// Allocate a new stack big enough for m->moreframesize bytes, +// copy m->moreargsize bytes to the new frame, +// and then act as though runtime·lessstack called the function at m->morepc. // // g->atomicstatus will be Grunning, Gsyscall or Gscanrunning, Gscansyscall upon entry. // If the GC is trying to stop this g then it will set preemptscan to true. @@ -879,14 +880,13 @@ void runtime·newstack(void) { int32 framesize, argsize, oldstatus, oldsize, newsize, nframes; - Stktop *top, *oldtop; + Stktop *top; byte *stk, *oldstk, *oldbase; uintptr sp; uintptr *src, *dst, *dstend; G *gp; Gobuf label, morebuf; void *moreargp; - bool newstackcall; if(g->m->forkstackguard) runtime·throw("split stack after fork"); @@ -894,6 +894,8 @@ runtime·newstack(void) runtime·printf("runtime: newstack called from g=%p\n" "\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n", g->m->morebuf.g, g->m, g->m->curg, g->m->g0, g->m->gsignal); + morebuf = g->m->morebuf; + runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g); runtime·throw("runtime: wrong goroutine in newstack"); } if(g->throwsplit) @@ -917,13 +919,8 @@ runtime·newstack(void) runtime·casgstatus(gp, oldstatus, Gwaiting); // oldstatus is not in a Gscan status gp->waitreason = runtime·gostringnocopy((byte*)"stack growth"); - newstackcall = framesize==1; - if(newstackcall) - framesize = 0; - // For newstackcall the context already points to beginning of runtime·newstackcall. - if(!newstackcall) - runtime·rewindmorestack(&gp->sched); + runtime·rewindmorestack(&gp->sched); if(gp->stackbase == 0) runtime·throw("nil stackbase"); @@ -1008,6 +1005,9 @@ runtime·newstack(void) // end of C code to trigger a copy as soon as C code exits. That way, we'll // have stack available if we get this deep again. } + + if(StackCopyAlways) + runtime·throw("split stack not allowed"); // allocate new segment. framesize += argsize; @@ -1033,17 +1033,6 @@ runtime·newstack(void) top->argp = moreargp; top->argsize = argsize; - // copy flag from panic - top->panic = gp->ispanic; - gp->ispanic = false; - - // if this isn't a panic, maybe we're splitting the stack for a panic. - // if we're splitting in the top frame, propagate the panic flag - // forward so that recover will know we're in a panic. - oldtop = (Stktop*)top->stackbase; - if(oldtop != nil && oldtop->panic && top->argp == (byte*)oldtop - oldtop->argsize - gp->panicwrap) - top->panic = true; - top->panicwrap = gp->panicwrap; gp->panicwrap = 0; @@ -1060,6 +1049,7 @@ runtime·newstack(void) while(dst < dstend) *dst++ = *src++; } + if(thechar == '5') { // caller would have saved its LR below args. sp -= sizeof(void*); @@ -1072,12 +1062,8 @@ runtime·newstack(void) label.sp = sp; label.pc = (uintptr)runtime·lessstack; label.g = g->m->curg; - if(newstackcall) - runtime·gostartcallfn(&label, (FuncVal*)g->m->cret); - else { - runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt); - gp->sched.ctxt = nil; - } + runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt); + gp->sched.ctxt = nil; runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Grunning or Gsyscall runtime·gogo(&label); |
