summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/proc.c')
-rw-r--r--src/pkg/runtime/proc.c211
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;
+}