diff options
author | Keith Randall <khr@golang.org> | 2014-09-11 13:46:58 -0700 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2014-09-11 13:46:58 -0700 |
commit | ccf42b15789beff3c355da0e1e6b71aedf1994d9 (patch) | |
tree | 05a99a7e69b9ff5ea5bd26e5fc0f382bb70f98eb /src | |
parent | 601b6c23d323ab059b6ea9d0a82d8e379ce8099e (diff) | |
download | go-ccf42b15789beff3c355da0e1e6b71aedf1994d9.tar.gz |
runtime: get rid of copyable check - all G frames are copyable.
Just go ahead and do it, if something is wrong we'll throw.
Also rip out cc-generated arg ptr maps, they are useless now.
LGTM=rsc
R=rsc
CC=golang-codereviews
https://codereview.appspot.com/133690045
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/cc/bv.c | 45 | ||||
-rw-r--r-- | src/cmd/cc/cc.h | 6 | ||||
-rw-r--r-- | src/cmd/cc/pgen.c | 163 | ||||
-rw-r--r-- | src/runtime/stack.c | 187 |
4 files changed, 31 insertions, 370 deletions
diff --git a/src/cmd/cc/bv.c b/src/cmd/cc/bv.c deleted file mode 100644 index db433de6a..000000000 --- a/src/cmd/cc/bv.c +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include <u.h> -#include "cc.h" - -enum { - WORDSIZE = sizeof(uint32), - WORDBITS = 32, -}; - -uintptr -bvsize(uintptr n) -{ - return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE; -} - -Bvec* -bvalloc(int32 n) -{ - Bvec *bv; - uintptr nbytes; - - if(n < 0) - fatal(Z, "bvalloc: initial size is negative\n"); - nbytes = sizeof(Bvec) + bvsize(n); - bv = malloc(nbytes); - if(bv == nil) - fatal(Z, "bvalloc: malloc failed\n"); - memset(bv, 0, nbytes); - bv->n = n; - return bv; -} - -void -bvset(Bvec *bv, int32 i) -{ - uint32 mask; - - if(i < 0 || i >= bv->n) - fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n); - mask = 1UL << (i % WORDBITS); - bv->b[i / WORDBITS] |= mask; -} diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index 1dae5acd9..9530f5cf6 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -762,12 +762,6 @@ int beq(Bits, Bits); int bset(Bits, uint); /* - * bv.c - */ -Bvec* bvalloc(int32 n); -void bvset(Bvec *bv, int32 i); - -/* * dpchk.c */ void dpcheck(Node*); diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index 4265b1b5e..db9aae916 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -31,30 +31,6 @@ #include "gc.h" #include "../../runtime/funcdata.h" -enum { BitsPerPointer = 2 }; - -static void dumpgcargs(Type *fn, Sym *sym); - -static Sym* -makefuncdatasym(char *namefmt, int64 funcdatakind) -{ - Node nod; - Sym *sym; - static int32 nsym; - static char namebuf[40]; - - snprint(namebuf, sizeof(namebuf), namefmt, nsym++); - sym = slookup(namebuf); - sym->class = CSTATIC; - memset(&nod, 0, sizeof nod); - nod.op = ONAME; - nod.sym = sym; - nod.class = CSTATIC; - gins(AFUNCDATA, nodconst(funcdatakind), &nod); - linksym(sym)->type = SRODATA; - return sym; -} - int hasdotdotdot(Type *t) { @@ -109,9 +85,6 @@ codgen(Node *n, Node *nn) { Prog *sp; Node *n1, nod, nod1; - Sym *gcargs; - Sym *gclocals; - int isvarargs; cursafe = 0; curarg = 0; @@ -135,16 +108,6 @@ codgen(Node *n, Node *nn) sp = p; /* - * generate funcdata symbol for this function. - * data is filled in at the end of codgen(). - */ - isvarargs = hasdotdotdot(thisfn); - gcargs = nil; - if(!isvarargs) - gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); - gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); - - /* * isolate first argument */ if(REGARG >= 0) { @@ -178,22 +141,6 @@ codgen(Node *n, Node *nn) if(thechar=='6' || thechar=='7') /* [sic] */ maxargsafe = xround(maxargsafe, 8); sp->to.offset += maxargsafe; - - if(!isvarargs) - dumpgcargs(thisfn, gcargs); - - // TODO(rsc): "stkoff" is not right. It does not account for - // the possibility of data stored in .safe variables. - // Unfortunately those move up and down just like - // the argument frame (and in fact dovetail with it) - // so the number we need is not available or even - // well-defined. Probably we need to make the safe - // area its own section. - // That said, we've been using stkoff for months - // and nothing too terrible has happened. - gextern(gclocals, nodconst(-stkoff), 0, 4); // locals - gclocals->type = typ(0, T); - gclocals->type->width = 4; } void @@ -673,113 +620,3 @@ bcomplex(Node *n, Node *c) boolgen(n, 1, Z); return 0; } - -// Updates the bitvector with a set bit for each pointer containing -// value in the type description starting at offset. -static void -walktype1(Type *t, int32 offset, Bvec *bv, int param) -{ - Type *t1; - int32 o; - int32 widthptr; - - widthptr = ewidth[TIND]; - switch(t->etype) { - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TINT: - case TUINT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TFLOAT: - case TDOUBLE: - // non-pointer types - for(o = 0; o < t->width; o++) - bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar - break; - - case TIND: - pointer: - // pointer types - if((offset + t->offset) % widthptr != 0) - yyerror("unaligned pointer"); - bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr - break; - - case TARRAY: - if(param) // unlike Go, C passes arrays by reference - goto pointer; - // array in struct or union is an actual array - for(o = 0; o < t->width; o += t->link->width) - walktype1(t->link, offset+o, bv, 0); - break; - - case TSTRUCT: - // build map recursively - for(t1 = t->link; t1 != T; t1 = t1->down) - walktype1(t1, offset, bv, 0); - break; - - case TUNION: - walktype1(t->link, offset, bv, 0); - break; - - default: - yyerror("can't handle arg type %s\n", tnames[t->etype]); - } -} - -// Compute a bit vector to describe the pointer containing locations -// in the argument list. Adds the data to gcsym and returns the offset -// of end of the bit vector. -static void -dumpgcargs(Type *fn, Sym *sym) -{ - Bvec *bv; - Type *t; - int32 i; - int32 argbytes; - int32 symoffset, argoffset; - - // Dump the length of the bitmap array. This value is always one for - // functions written in C. - symoffset = 0; - gextern(sym, nodconst(1), symoffset, 4); - symoffset += 4; - argbytes = (argsize(1) + ewidth[TIND] - 1); - bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer); - argoffset = 0; - if(hasdotdotdot(thisfn)) - argoffset = align(0, fn->link, Aarg0, nil); - if(argoffset > 0) { - // The C calling convention returns structs by copying them to a - // location pointed to by a hidden first argument. This first - // argument is a pointer. - if(argoffset != ewidth[TIND]) - yyerror("passbyptr arg not the right size"); - bvset(bv, 1); // 2 = live ptr - } - for(t = fn->down; t != T; t = t->down) { - if(t->etype == TVOID) - continue; - argoffset = align(argoffset, t, Aarg1, nil); - walktype1(t, argoffset, bv, 1); - argoffset = align(argoffset, t, Aarg2, nil); - } - // Dump the length of the bitmap. - gextern(sym, nodconst(bv->n), symoffset, 4); - symoffset += 4; - // Dump the words of the bitmap. - for(i = 0; i < bv->n; i += 32) { - gextern(sym, nodconst(bv->b[i/32]), symoffset, 4); - symoffset += 4; - } - free(bv); - // Finalize the gc symbol. - sym->type = typ(0, T); - sym->type->width = symoffset; -} diff --git a/src/runtime/stack.c b/src/runtime/stack.c index 2e0c91de0..cc2857ac8 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -331,145 +331,22 @@ mapnames[] = { // | args to callee | // +------------------+ <- frame->sp // -// (arm: TODO) - -typedef struct CopyableInfo CopyableInfo; -struct CopyableInfo { - Stack stk; - int32 frames; // count of copyable frames (-1 = not copyable) -}; +// (arm) +// +------------------+ +// | args from caller | +// +------------------+ <- frame->argp +// | caller's retaddr | +// +------------------+ <- frame->varp +// | locals | +// +------------------+ +// | args to callee | +// +------------------+ +// | return address | +// +------------------+ <- frame->sp void runtime·main(void); void runtime·switchtoM(void(*)(void)); -static bool -checkframecopy(Stkframe *frame, void *arg) -{ - CopyableInfo *cinfo; - Func *f; - StackMap *stackmap; - - cinfo = arg; - f = frame->fn; - if(StackDebug >= 2) - runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", runtime·funcname(f), frame->sp, frame->fp, cinfo->stk.lo, cinfo->stk.hi); - // if we're not in the segment any more, return immediately. - if(frame->varp < cinfo->stk.lo || frame->varp >= cinfo->stk.hi) { - if(StackDebug >= 2) - runtime·printf(" <next segment>\n"); - return false; // stop traceback - } - if(f->entry == (uintptr)runtime·switchtoM) { - // A special routine at the bottom of stack of a goroutine that does onM call. - // We will allow it to be copied even though we don't - // have full GC info for it (because it is written in asm). - cinfo->frames++; - return true; - } - if((byte*)frame->varp != (byte*)frame->sp) { // not in prologue (and has at least one local or outarg) - stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); - if(stackmap == nil) { - cinfo->frames = -1; - runtime·printf("runtime: copystack: no locals info for %s\n", runtime·funcname(f)); - return false; - } - if(stackmap->n <= 0) { - cinfo->frames = -1; - runtime·printf("runtime: copystack: locals size info only for %s\n", runtime·funcname(f)); - return false; - } - } - if(frame->arglen != 0) { - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap == nil) { - cinfo->frames = -1; - runtime·printf("runtime: copystack: no arg info for %s\n", runtime·funcname(f)); - return false; - } - } - cinfo->frames++; - return true; // this frame is ok; keep going -} - -// If the top segment of the stack contains an uncopyable -// frame, return -1. Otherwise return the number of frames -// in the top segment, all of which are copyable. -static int32 -copyabletopsegment(G *gp) -{ - CopyableInfo cinfo; - Defer *d; - Func *f; - FuncVal *fn; - StackMap *stackmap; - bool (*cb)(Stkframe*, void*); - - if(gp->stack.lo == 0) - runtime·throw("missing stack in copyabletopsegment"); - cinfo.stk = gp->stack; - cinfo.frames = 0; - - // Check that each frame is copyable. As a side effect, - // count the frames. - cb = checkframecopy; - runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &cinfo, false); - if(StackDebug >= 1 && cinfo.frames != -1) - runtime·printf("copystack: %d copyable frames\n", cinfo.frames); - - if(cinfo.frames == -1) - return -1; - - // Check to make sure all Defers are copyable - for(d = gp->defer; d != nil; d = d->link) { - if(cinfo.stk.lo <= (uintptr)d && (uintptr)d < cinfo.stk.hi) { - // Defer is on the stack. Its copyableness has - // been established during stack walking. - // For now, this only happens with the Defer in runtime.main. - continue; - } - if(d->argp < cinfo.stk.lo || cinfo.stk.hi <= d->argp) - break; // a defer for the next segment - fn = d->fn; - if(fn == nil) // See issue 8047 - continue; - f = runtime·findfunc((uintptr)fn->fn); - if(f == nil) { - runtime·printf("runtime: copystack: no func for deferred pc %p\n", fn->fn); - return -1; - } - - // Check to make sure we have an args pointer map for the defer's args. - // We only need the args map, but we check - // for the locals map also, because when the locals map - // isn't provided it means the ptr map came from C and - // C (particularly, cgo) lies to us. See issue 7695. - stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); - if(stackmap == nil || stackmap->n <= 0) { - 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) { - runtime·printf("runtime: copystack: no local info for deferred %s\n", runtime·funcname(f)); - return -1; - } - - if(cinfo.stk.lo <= (uintptr)fn && (uintptr)fn < cinfo.stk.hi) { - // FuncVal is on the stack. Again, its copyableness - // was established during stack walking. - continue; - } - // The FuncVal may have pointers in it, but fortunately for us - // the compiler won't put pointers into the stack in a - // heap-allocated FuncVal. - // One day if we do need to check this, we'll need maps of the - // pointerness of the closure args. The only place we have that map - // right now is in the gc program for the FuncVal. Ugh. - } - - return cinfo.frames; -} - typedef struct AdjustInfo AdjustInfo; struct AdjustInfo { Stack old; @@ -573,8 +450,12 @@ adjustframe(Stkframe *frame, void *arg) f = frame->fn; if(StackDebug >= 2) runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc); - if(f->entry == (uintptr)runtime·switchtoM) + if(f->entry == (uintptr)runtime·switchtoM) { + // A special routine at the bottom of stack of a goroutine that does an onM call. + // We will allow it to be copied even though we don't + // have full GC info for it (because it is written in asm). return true; + } targetpc = frame->continpc; if(targetpc == 0) { // Frame is dead. @@ -648,11 +529,10 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) runtime·printf("runtime: adjustdefers argp=%p stk=%p %p\n", d->argp, adjinfo->old.lo, adjinfo->old.hi); runtime·throw("adjustdefers: unexpected argp"); } + d->argp += adjinfo->delta; fn = d->fn; if(fn == nil) { - // Defer of nil function. It will panic when run, and there - // aren't any args to adjust. See issue 8047. - d->argp += adjinfo->delta; + // Defer of nil function. It will panic when run. See issue 8047. continue; } f = runtime·findfunc((uintptr)fn->fn); @@ -675,7 +555,11 @@ adjustdefers(G *gp, AdjustInfo *adjinfo) bv = runtime·stackmapdata(stackmap, 0); adjustpointers(d->args, &bv, adjinfo, f); } - d->argp += adjinfo->delta; + // The FuncVal may have pointers in it, but fortunately for us + // the compiler won't put pointers into the stack in a + // heap-allocated FuncVal. + // One day if we do need to check this, we can use the gc bits in the + // heap to do the right thing (although getting the size will be expensive). } } @@ -707,10 +591,9 @@ adjustsudogs(G *gp, AdjustInfo *adjinfo) } } -// Copies the top stack segment of gp to a new stack segment of a -// different size. The top segment must contain nframes frames. +// Copies gp's stack to a new stack of a different size. static void -copystack(G *gp, uintptr nframes, uintptr newsize) +copystack(G *gp, uintptr newsize) { Stack old, new; uintptr used; @@ -735,7 +618,7 @@ copystack(G *gp, uintptr nframes, uintptr newsize) adjinfo.old = old; adjinfo.delta = new.hi - old.hi; cb = adjustframe; - runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, &cb, &adjinfo, false); + runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, false); // adjust other miscellaneous things that have pointers into stacks. adjustctxt(gp, &adjinfo); @@ -785,7 +668,7 @@ runtime·round2(int32 x) void runtime·newstack(void) { - int32 oldsize, newsize, nframes; + int32 oldsize, newsize; uintptr sp; G *gp; Gobuf morebuf; @@ -867,10 +750,6 @@ runtime·newstack(void) } // Allocate a bigger segment and move the stack. - nframes = copyabletopsegment(gp); - if(nframes == -1) - runtime·throw("unable to grow stack"); - oldsize = gp->stack.hi - gp->stack.lo; newsize = oldsize * 2; if(newsize > runtime·maxstacksize) { @@ -880,7 +759,7 @@ runtime·newstack(void) // Note that the concurrent GC might be scanning the stack as we try to replace it. // copystack takes care of the appropriate coordination with the stack scanner. - copystack(gp, nframes, newsize); + copystack(gp, newsize); if(StackDebug >= 1) runtime·printf("stack grow done\n"); runtime·casgstatus(gp, Gwaiting, Grunning); @@ -913,14 +792,13 @@ runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv) void runtime·shrinkstack(G *gp) { - int32 nframes; uintptr used, oldsize, newsize; if(runtime·readgstatus(gp) == Gdead) return; if(gp->stack.lo == 0) runtime·throw("missing stack in shrinkstack"); - //return; // TODO: why does this happen? + oldsize = gp->stack.hi - gp->stack.lo; newsize = oldsize / 2; if(newsize < FixedStack) @@ -938,10 +816,7 @@ runtime·shrinkstack(G *gp) #endif if(StackDebug > 0) runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uint64)newsize); - nframes = copyabletopsegment(gp); - if(nframes == -1) - return; - copystack(gp, nframes, newsize); + copystack(gp, newsize); } static void badc(void); |