aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/stack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/stack.c')
-rw-r--r--src/runtime/stack.c92
1 files changed, 61 insertions, 31 deletions
diff --git a/src/runtime/stack.c b/src/runtime/stack.c
index 143b645e42..8562b94076 100644
--- a/src/runtime/stack.c
+++ b/src/runtime/stack.c
@@ -32,8 +32,8 @@ enum
// Stacks are assigned an order according to size.
// order = log_2(size/FixedStack)
// There is a free list for each order.
-static MSpan stackpool[NumStackOrders];
-static Mutex stackpoolmu;
+MSpan runtime·stackpool[NumStackOrders];
+Mutex runtime·stackpoolmu;
// TODO: one lock per order?
void
@@ -45,7 +45,7 @@ runtime·stackinit(void)
runtime·throw("cache size must be a multiple of page size");
for(i = 0; i < NumStackOrders; i++)
- runtime·MSpanList_Init(&stackpool[i]);
+ runtime·MSpanList_Init(&runtime·stackpool[i]);
}
// Allocates a stack from the free pool. Must be called with
@@ -58,7 +58,7 @@ poolalloc(uint8 order)
MLink *x;
uintptr i;
- list = &stackpool[order];
+ list = &runtime·stackpool[order];
s = list->next;
if(s == list) {
// no free stacks. Allocate another span worth.
@@ -99,7 +99,7 @@ poolfree(MLink *x, uint8 order)
runtime·throw("freeing stack not in a stack span");
if(s->freelist == nil) {
// s will now have a free stack
- runtime·MSpanList_Insert(&stackpool[order], s);
+ runtime·MSpanList_Insert(&runtime·stackpool[order], s);
}
x->next = s->freelist;
s->freelist = x;
@@ -127,14 +127,14 @@ stackcacherefill(MCache *c, uint8 order)
// Grab half of the allowed capacity (to prevent thrashing).
list = nil;
size = 0;
- runtime·lock(&stackpoolmu);
+ runtime·lock(&runtime·stackpoolmu);
while(size < StackCacheSize/2) {
x = poolalloc(order);
x->next = list;
list = x;
size += FixedStack << order;
}
- runtime·unlock(&stackpoolmu);
+ runtime·unlock(&runtime·stackpoolmu);
c->stackcache[order].list = list;
c->stackcache[order].size = size;
@@ -150,14 +150,14 @@ stackcacherelease(MCache *c, uint8 order)
runtime·printf("stackcacherelease order=%d\n", order);
x = c->stackcache[order].list;
size = c->stackcache[order].size;
- runtime·lock(&stackpoolmu);
+ runtime·lock(&runtime·stackpoolmu);
while(size > StackCacheSize/2) {
y = x->next;
poolfree(x, order);
x = y;
size -= FixedStack << order;
}
- runtime·unlock(&stackpoolmu);
+ runtime·unlock(&runtime·stackpoolmu);
c->stackcache[order].list = x;
c->stackcache[order].size = size;
}
@@ -170,7 +170,7 @@ runtime·stackcache_clear(MCache *c)
if(StackDebug >= 1)
runtime·printf("stackcache clear\n");
- runtime·lock(&stackpoolmu);
+ runtime·lock(&runtime·stackpoolmu);
for(order = 0; order < NumStackOrders; order++) {
x = c->stackcache[order].list;
while(x != nil) {
@@ -181,7 +181,7 @@ runtime·stackcache_clear(MCache *c)
c->stackcache[order].list = nil;
c->stackcache[order].size = 0;
}
- runtime·unlock(&stackpoolmu);
+ runtime·unlock(&runtime·stackpoolmu);
}
Stack
@@ -227,9 +227,9 @@ runtime·stackalloc(uint32 n)
// procresize. Just get a stack from the global pool.
// Also don't touch stackcache during gc
// as it's flushed concurrently.
- runtime·lock(&stackpoolmu);
+ runtime·lock(&runtime·stackpoolmu);
x = poolalloc(order);
- runtime·unlock(&stackpoolmu);
+ runtime·unlock(&runtime·stackpoolmu);
} else {
x = c->stackcache[order].list;
if(x == nil) {
@@ -289,9 +289,9 @@ runtime·stackfree(Stack stk)
x = (MLink*)v;
c = g->m->mcache;
if(c == nil || g->m->gcing || g->m->helpgc) {
- runtime·lock(&stackpoolmu);
+ runtime·lock(&runtime·stackpoolmu);
poolfree(x, order);
- runtime·unlock(&stackpoolmu);
+ runtime·unlock(&runtime·stackpoolmu);
} else {
if(c->stackcache[order].size >= StackCacheSize)
stackcacherelease(c, order);
@@ -463,7 +463,7 @@ adjustframe(Stkframe *frame, void *arg)
StackMap *stackmap;
int32 pcdata;
BitVector bv;
- uintptr targetpc;
+ uintptr targetpc, size, minsize;
adjinfo = arg;
targetpc = frame->continpc;
@@ -486,27 +486,47 @@ adjustframe(Stkframe *frame, void *arg)
if(pcdata == -1)
pcdata = 0; // in prologue
- // adjust local pointers
- if((byte*)frame->varp != (byte*)frame->sp) {
+ // Adjust local variables if stack frame has been allocated.
+ size = frame->varp - frame->sp;
+ if(thechar != '6' && thechar != '8')
+ minsize = sizeof(uintptr);
+ else
+ minsize = 0;
+ if(size > minsize) {
stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
- if(stackmap == nil)
- runtime·throw("no locals info");
- if(stackmap->n <= 0)
- runtime·throw("locals size info only");
+ if(stackmap == nil || stackmap->n <= 0) {
+ runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size);
+ runtime·throw("missing stackmap");
+ }
+ // Locals bitmap information, scan just the pointers in locals.
+ if(pcdata < 0 || pcdata >= stackmap->n) {
+ // don't know where we are
+ runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n",
+ pcdata, stackmap->n, runtime·funcname(f), targetpc);
+ runtime·throw("bad symbol table");
+ }
bv = runtime·stackmapdata(stackmap, pcdata);
+ size = (bv.n * PtrSize) / BitsPerPointer;
if(StackDebug >= 3)
runtime·printf(" locals\n");
- adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv, adjinfo, f);
+ adjustpointers((byte**)(frame->varp - size), &bv, adjinfo, f);
}
- // adjust inargs and outargs
- if(frame->arglen != 0) {
+
+ // Adjust arguments.
+ if(frame->arglen > 0) {
if(frame->argmap != nil) {
bv = *frame->argmap;
} else {
stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
- if(stackmap == nil) {
- runtime·printf("size %d\n", (int32)frame->arglen);
- runtime·throw("no arg info");
+ if(stackmap == nil || stackmap->n <= 0) {
+ runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
+ runtime·throw("missing stackmap");
+ }
+ if(pcdata < 0 || pcdata >= stackmap->n) {
+ // don't know where we are
+ runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n",
+ pcdata, stackmap->n, runtime·funcname(f), targetpc);
+ runtime·throw("bad symbol table");
}
bv = runtime·stackmapdata(stackmap, pcdata);
}
@@ -675,7 +695,7 @@ runtime·newstack(void)
runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g);
runtime·throw("runtime: wrong goroutine in newstack");
}
- if(g->throwsplit)
+ if(g->m->curg->throwsplit)
runtime·throw("runtime: stack split at bad time");
// The goroutine must be executing in order to call newstack,
@@ -786,8 +806,16 @@ runtime·shrinkstack(G *gp)
{
uintptr used, oldsize, newsize;
- if(runtime·readgstatus(gp) == Gdead)
+ if(runtime·readgstatus(gp) == Gdead) {
+ if(gp->stack.lo != 0) {
+ // Free whole stack - it will get reallocated
+ // if G is used again.
+ runtime·stackfree(gp->stack);
+ gp->stack.lo = 0;
+ gp->stack.hi = 0;
+ }
return;
+ }
if(gp->stack.lo == 0)
runtime·throw("missing stack in shrinkstack");
@@ -799,7 +827,9 @@ runtime·shrinkstack(G *gp)
if(used >= oldsize / 4)
return; // still using at least 1/4 of the segment.
- if(gp->syscallsp != 0) // TODO: can we handle this case?
+ // We can't copy the stack if we're in a syscall.
+ // The syscall might have pointers into the stack.
+ if(gp->syscallsp != 0)
return;
#ifdef GOOS_windows