diff options
Diffstat (limited to 'src/pkg/runtime/proc.c')
-rw-r--r-- | src/pkg/runtime/proc.c | 211 |
1 files changed, 86 insertions, 125 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index e9a19d950..998cbc7bc 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -470,8 +470,8 @@ scheduler(void) d = gp->defer; gp->defer = d->link; - // unwind to the stack frame with d->sp in it. - unwindstack(gp, d->sp); + // unwind to the stack frame with d's arguments in it. + unwindstack(gp, d->argp); // make the deferproc for this d return again, // this time returning 1. function will jump to @@ -481,7 +481,11 @@ scheduler(void) // each call to deferproc. // (the pc we're returning to does pop pop // before it tests the return value.) - gp->sched.sp = runtime·getcallersp(d->sp - 2*sizeof(uintptr)); + // on the arm there are 2 saved LRs mixed in too. + if(thechar == '5') + gp->sched.sp = (byte*)d->argp - 4*sizeof(uintptr); + else + gp->sched.sp = (byte*)d->argp - 2*sizeof(uintptr); gp->sched.pc = d->pc; gp->status = Grunning; runtime·free(d); @@ -633,7 +637,6 @@ void runtime·startcgocallback(G* g1) { Defer *d; - uintptr arg; runtime·lock(&runtime·sched); g1->status = Grunning; @@ -675,80 +678,11 @@ runtime·endcgocallback(G* g1) runtime·free(d); } -/* - * stack layout parameters. - * known to linkers. - * - * g->stackguard is set to point StackGuard bytes - * above the bottom of the stack. each function - * compares its stack pointer against g->stackguard - * to check for overflow. to cut one instruction from - * the check sequence for functions with tiny frames, - * the stack is allowed to protrude StackSmall bytes - * below the stack guard. functions with large frames - * don't bother with the check and always call morestack. - * the sequences are: - * - * guard = g->stackguard - * frame = function's stack frame size - * argsize = size of function arguments (call + return) - * - * stack frame size <= StackSmall: - * CMPQ guard, SP - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL sys.morestack(SB) - * - * stack frame size > StackSmall but < StackBig - * LEAQ (frame-StackSmall)(SP), R0 - * CMPQ guard, R0 - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL sys.morestack(SB) - * - * stack frame size >= StackBig: - * MOVQ m->morearg, $((argsize << 32) | frame) - * CALL sys.morestack(SB) - * - * the bottom StackGuard - StackSmall bytes are important: - * there has to be enough room to execute functions that - * refuse to check for stack overflow, either because they - * need to be adjacent to the actual caller's frame (sys.deferproc) - * or because they handle the imminent stack overflow (sys.morestack). - * - * for example, sys.deferproc might call malloc, - * which does one of the above checks (without allocating a full frame), - * which might trigger a call to sys.morestack. - * this sequence needs to fit in the bottom section of the stack. - * on amd64, sys.morestack's frame is 40 bytes, and - * sys.deferproc's frame is 56 bytes. that fits well within - * the StackGuard - StackSmall = 128 bytes at the bottom. - * there may be other sequences lurking or yet to be written - * that require more stack. sys.morestack checks to make sure - * the stack has not completely overflowed and should - * catch such sequences. - */ -enum -{ - // byte offset of stack guard (g->stackguard) above bottom of stack. - StackGuard = 256, - - // checked frames are allowed to protrude below the guard by - // this many bytes. this saves an instruction in the checking - // sequence when the stack frame is tiny. - StackSmall = 128, - - // extra space in the frame (beyond the function for which - // the frame is allocated) is assumed not to be much bigger - // than this amount. it may not be used efficiently if it is. - StackBig = 4096, -}; - void runtime·oldstack(void) { Stktop *top, old; - uint32 args; + uint32 argsize; byte *sp; G *g1; static int32 goid; @@ -759,15 +693,15 @@ runtime·oldstack(void) top = (Stktop*)g1->stackbase; sp = (byte*)top; old = *top; - args = old.args; - if(args > 0) { - sp -= args; - runtime·mcpy(top->fp, sp, args); + argsize = old.argsize; + if(argsize > 0) { + sp -= argsize; + runtime·mcpy(top->argp, sp, argsize); } goid = old.gobuf.g->goid; // fault if g is bad, before gogo - if(old.free) - runtime·stackfree(g1->stackguard - StackGuard); + if(old.free != 0) + runtime·stackfree(g1->stackguard - StackGuard, old.free); g1->stackbase = old.stackbase; g1->stackguard = old.stackguard; @@ -777,40 +711,45 @@ runtime·oldstack(void) void runtime·newstack(void) { - int32 frame, args; + int32 framesize, argsize; Stktop *top; byte *stk, *sp; G *g1; Gobuf label; - bool free; + bool reflectcall; + uintptr free; - frame = m->moreframe; - args = m->moreargs; + framesize = m->moreframesize; + argsize = m->moreargsize; g1 = m->curg; - if(m->morebuf.sp < g1->stackguard - StackGuard) - runtime·throw("split stack overflow"); + if(m->morebuf.sp < g1->stackguard - StackGuard) { + runtime·printf("runtime: split stack overflow: %p < %p\n", m->morebuf.sp, g1->stackguard - StackGuard); + runtime·throw("runtime: split stack overflow"); + } + + reflectcall = framesize==1; + if(reflectcall) + framesize = 0; - if(frame == 1 && args > 0 && m->morebuf.sp - sizeof(Stktop) - args - 32 > g1->stackguard) { - // special case: called from reflect.call (frame == 1) + if(reflectcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > g1->stackguard) { + // special case: called from reflect.call (framesize==1) // to call code with an arbitrary argument size, // and we have enough space on the current stack. // the new Stktop* is necessary to unwind, but // we don't need to create a new segment. top = (Stktop*)(m->morebuf.sp - sizeof(*top)); stk = g1->stackguard - StackGuard; - free = false; + free = 0; } else { // allocate new segment. - if(frame == 1) // failed reflect.call hint - frame = 0; - frame += args; - if(frame < StackBig) - frame = StackBig; - frame += 1024; // room for more functions, Stktop. - stk = runtime·stackalloc(frame); - top = (Stktop*)(stk+frame-sizeof(*top)); - free = true; + framesize += argsize; + if(framesize < StackBig) + framesize = StackBig; + framesize += StackExtra; // room for more functions, Stktop. + stk = runtime·stackalloc(framesize); + top = (Stktop*)(stk+framesize-sizeof(*top)); + free = framesize; } //printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n", @@ -819,8 +758,8 @@ runtime·newstack(void) top->stackbase = g1->stackbase; top->stackguard = g1->stackguard; top->gobuf = m->morebuf; - top->fp = m->morefp; - top->args = args; + top->argp = m->moreargp; + top->argsize = argsize; top->free = free; // copy flag from panic @@ -831,9 +770,14 @@ runtime·newstack(void) g1->stackguard = stk + StackGuard; sp = (byte*)top; - if(args > 0) { - sp -= args; - runtime·mcpy(sp, m->morefp, args); + if(argsize > 0) { + sp -= argsize; + runtime·mcpy(sp, m->moreargp, argsize); + } + if(thechar == '5') { + // caller would have saved its LR below args. + sp -= sizeof(void*); + *(void**)sp = nil; } // Continue as if lessstack had just called m->morepc @@ -876,7 +820,13 @@ runtime·malg(int32 stacksize) void runtime·newproc(int32 siz, byte* fn, ...) { - runtime·newproc1(fn, (byte*)(&fn+1), siz, 0); + byte *argp; + + if(thechar == '5') + argp = (byte*)(&fn+2); // skip caller's saved LR + else + argp = (byte*)(&fn+1); + runtime·newproc1(fn, argp, siz, 0); } G* @@ -899,7 +849,7 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret) if(newg->stackguard - StackGuard != newg->stack0) runtime·throw("invalid stack in newg"); } else { - newg = runtime·malg(4096); + newg = runtime·malg(StackBig); newg->status = Gwaiting; newg->alllink = runtime·allg; runtime·allg = newg; @@ -908,6 +858,11 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret) sp = newg->stackbase; sp -= siz; runtime·mcpy(sp, argp, narg); + if(thechar == '5') { + // caller's LR + sp -= sizeof(void*); + *(void**)sp = nil; + } newg->sched.sp = sp; newg->sched.pc = (byte*)runtime·goexit; @@ -933,10 +888,13 @@ runtime·deferproc(int32 siz, byte* fn, ...) d = runtime·malloc(sizeof(*d) + siz - sizeof(d->args)); d->fn = fn; - d->sp = (byte*)(&fn+1); d->siz = siz; d->pc = runtime·getcallerpc(&siz); - runtime·mcpy(d->args, d->sp, d->siz); + if(thechar == '5') + d->argp = (byte*)(&fn+2); // skip caller's saved link register + else + d->argp = (byte*)(&fn+1); + runtime·mcpy(d->args, d->argp, d->siz); d->link = g->defer; g->defer = d; @@ -955,19 +913,19 @@ void runtime·deferreturn(uintptr arg0) { Defer *d; - byte *sp, *fn; + byte *argp, *fn; d = g->defer; if(d == nil) return; - sp = runtime·getcallersp(&arg0); - if(d->sp != sp) + argp = (byte*)&arg0; + if(d->argp != argp) return; - runtime·mcpy(d->sp, d->args, d->siz); + runtime·mcpy(argp, d->args, d->siz); g->defer = d->link; fn = d->fn; runtime·free(d); - runtime·jmpdefer(fn, sp); + runtime·jmpdefer(fn, argp); } static void @@ -983,7 +941,7 @@ rundefer(void) } // Free stack frames until we hit the last one -// or until we find the one that contains the sp. +// or until we find the one that contains the argp. static void unwindstack(G *gp, byte *sp) { @@ -1000,8 +958,8 @@ unwindstack(G *gp, byte *sp) break; gp->stackbase = top->stackbase; gp->stackguard = top->stackguard; - if(top->free) - runtime·stackfree(stk); + if(top->free != 0) + runtime·stackfree(stk, top->free); } if(sp != nil && (sp < gp->stackguard - StackGuard || gp->stackbase < sp)) { @@ -1043,12 +1001,11 @@ runtime·panic(Eface e) // take defer off list in case of recursive panic g->defer = d->link; g->ispanic = true; // rock for newstack, where reflect.call ends up - if(thechar == '5') - reflect·call(d->fn, d->args+4, d->siz-4); // reflect.call does not expect LR - else - reflect·call(d->fn, d->args, d->siz); + reflect·call(d->fn, d->args, d->siz); if(p->recovered) { g->panic = p->link; + if(g->panic == nil) // must be done with signal + g->sig = 0; runtime·free(p); // put recovering defer back on list // for scheduler to find. @@ -1068,13 +1025,11 @@ runtime·panic(Eface e) #pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */ void -runtime·recover(byte *fp, Eface ret) +runtime·recover(byte *argp, Eface ret) { Stktop *top, *oldtop; Panic *p; - fp = runtime·getcallersp(fp); - // Must be a panic going on. if((p = g->panic) == nil || p->recovered) goto nomatch; @@ -1097,11 +1052,11 @@ runtime·recover(byte *fp, Eface ret) // allocated a second segment (see below), // the fp is slightly above top - top->args. // That condition can't happen normally though - // (stack pointer go down, not up), so we can accept + // (stack pointers go down, not up), so we can accept // any fp between top and top - top->args as // indicating the top of the segment. top = (Stktop*)g->stackbase; - if(fp < (byte*)top - top->args || (byte*)top < fp) + if(argp < (byte*)top - top->argsize || (byte*)top < argp) goto nomatch; // The deferred call makes a new segment big enough @@ -1117,7 +1072,7 @@ runtime·recover(byte *fp, Eface ret) // bytes above top->fp) abuts the old top of stack. // This is a correct test for both closure and non-closure code. oldtop = (Stktop*)top->stackbase; - if(oldtop != nil && top->fp == (byte*)oldtop - top->args) + if(oldtop != nil && top->argp == (byte*)oldtop - top->argsize) top = oldtop; // Now we have the segment that was created to @@ -1237,3 +1192,9 @@ runtime·Goroutines(int32 ret) ret = runtime·sched.gcount; FLUSH(&ret); } + +int32 +runtime·mcount(void) +{ + return runtime·sched.mcount; +} |