From: Keith Randall Date: Fri, 17 Jan 2014 22:48:45 +0000 (-0800) Subject: runtime, cmd/gc: Get rid of vararg channel calls. X-Git-Tag: go1.3beta1~937 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6f6a9445c93bfbfd05ea9b7880137c02618bedbd;p=gostls13.git runtime, cmd/gc: Get rid of vararg channel calls. Vararg C calls present a problem for the GC because the argument types are not derivable from the signature. Remove them by passing pointers to channel elements instead of the channel elements directly. R=golang-codereviews, gobot, rsc, dvyukov CC=golang-codereviews https://golang.org/cl/53430043 --- diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index 1b0297d7ca..4955231c20 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -77,11 +77,11 @@ char *runtimeimport = "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" "func @\"\".mapiternext (@\"\".hiter·1 *any)\n" "func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" - "func @\"\".chanrecv1 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any) (@\"\".elem·1 any)\n" - "func @\"\".chanrecv2 (@\"\".chanType·3 *byte, @\"\".hchan·4 <-chan any) (@\"\".elem·1 any, @\"\".received·2 bool)\n" - "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 any)\n" + "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" + "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" + "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" "func @\"\".closechan (@\"\".hchan·1 any)\n" - "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 any) (? bool)\n" + "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n" "func @\"\".newselect (@\"\".size·2 int32) (@\"\".sel·1 *byte)\n" diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 852a545a91..c65365f55a 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -101,12 +101,12 @@ func mapiternext(hiter *any) // *byte is really *runtime.Type func makechan(chanType *byte, hint int64) (hchan chan any) -func chanrecv1(chanType *byte, hchan <-chan any) (elem any) -func chanrecv2(chanType *byte, hchan <-chan any) (elem any, received bool) -func chansend1(chanType *byte, hchan chan<- any, elem any) +func chanrecv1(chanType *byte, hchan <-chan any, elem *any) +func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool +func chansend1(chanType *byte, hchan chan<- any, elem *any) func closechan(hchan any) -func selectnbsend(chanType *byte, hchan chan<- any, elem any) bool +func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index cd3de8c7be..35da0557b6 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -252,8 +252,20 @@ walkselect(Node *sel) case OSEND: // if c != nil && selectnbsend(c, v) { body } else { default body } ch = cheapexpr(n->left, &r->ninit); + a = n->right; + a = assignconv(a, ch->type->type, "select chan send"); + walkexpr(&a, &r->ninit); + if(islvalue(a)) { + a = nod(OADDR, a, N); + } else { + var = temp(a->type); + tmp = nod(OAS, var, a); + typecheck(&tmp, Etop); + r->ninit = list(r->ninit, tmp); + a = nod(OADDR, var, N); + } r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type), - types[TBOOL], &r->ninit, typename(ch->type), ch, n->right); + types[TBOOL], &r->ninit, typename(ch->type), ch, a); break; case OSELRECV: diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index e1a909ce69..eb5a3f1b6b 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -163,7 +163,6 @@ walkstmt(Node **np) case OCALLFUNC: case ODELETE: case OSEND: - case ORECV: case OPRINT: case OPRINTN: case OPANIC: @@ -179,6 +178,21 @@ walkstmt(Node **np) n->op = OEMPTY; // don't leave plain values as statements. break; + case ORECV: + // special case for a receive where we throw away + // the value received. + if(n->typecheck == 0) + fatal("missing typecheck: %+N", n); + init = n->ninit; + n->ninit = nil; + + walkexpr(&n->left, &init); + n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil()); + walkexpr(&n, &init); + + addinit(&n, init); + break; + case OBREAK: case ODCL: case OCONTINUE: @@ -593,6 +607,7 @@ walkexpr(Node **np, NodeList **init) goto ret; case OAS2: + as2: *init = concat(*init, n->ninit); n->ninit = nil; walkexprlistsafe(n->list, init); @@ -603,7 +618,6 @@ walkexpr(Node **np, NodeList **init) goto ret; case OAS2FUNC: - as2func: // a,b,... = fn() *init = concat(*init, n->ninit); n->ninit = nil; @@ -645,11 +659,13 @@ walkexpr(Node **np, NodeList **init) r = n->rlist->n; walkexprlistsafe(n->list, init); walkexpr(&r->left, init); + var = temp(r->left->type->type); + n1 = nod(OADDR, var, N); fn = chanfn("chanrecv2", 2, r->left->type); - r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left); - n->rlist->n = r; - n->op = OAS2FUNC; - goto as2func; + r = mkcall1(fn, types[TBOOL], init, typename(r->left->type), r->left, n1); + n->op = OAS2; + n->rlist = concat(list1(var), list1(r)); + goto as2; case OAS2MAPR: // a,b = m[i]; @@ -1149,8 +1165,12 @@ walkexpr(Node **np, NodeList **init) case ORECV: walkexpr(&n->left, init); - walkexpr(&n->right, init); - n = mkcall1(chanfn("chanrecv1", 2, n->left->type), n->type, init, typename(n->left->type), n->left); + var = temp(n->left->type->type); + n1 = nod(OADDR, var, N); + n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1); + walkexpr(&n, init); + *init = list(*init, n); + n = var; goto ret; case OSLICE: @@ -1427,7 +1447,19 @@ walkexpr(Node **np, NodeList **init) goto ret; case OSEND: - n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n->right); + n1 = n->right; + n1 = assignconv(n1, n->left->type->type, "chan send"); + walkexpr(&n1, init); + if(islvalue(n1)) { + n1 = nod(OADDR, n1, N); + } else { + var = temp(n1->type); + n1 = nod(OAS, var, n1); + typecheck(&n1, Etop); + *init = list(*init, n1); + n1 = nod(OADDR, var, N); + } + n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1); goto ret; case OCLOSURE: diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c index cee35c3efd..d90dc78e16 100644 --- a/src/pkg/runtime/chan.c +++ b/src/pkg/runtime/chan.c @@ -430,35 +430,31 @@ closed: runtime·blockevent(mysg.releasetime - t0, 2); } -// chansend1(hchan *chan any, elem any); +// chansend1(hchan *chan any, elem *any); #pragma textflag NOSPLIT void -runtime·chansend1(ChanType *t, Hchan* c, ...) +runtime·chansend1(ChanType *t, Hchan* c, byte *v) { - runtime·chansend(t, c, (byte*)(&c+1), nil, runtime·getcallerpc(&t)); + runtime·chansend(t, c, v, nil, runtime·getcallerpc(&t)); } -// chanrecv1(hchan *chan any) (elem any); +// chanrecv1(hchan *chan any, elem *any); #pragma textflag NOSPLIT void -runtime·chanrecv1(ChanType *t, Hchan* c, ...) +runtime·chanrecv1(ChanType *t, Hchan* c, byte *v) { - runtime·chanrecv(t, c, (byte*)(&c+1), nil, nil); + runtime·chanrecv(t, c, v, nil, nil); } -// chanrecv2(hchan *chan any) (elem any, received bool); +// chanrecv2(hchan *chan any, elem *any) (received bool); #pragma textflag NOSPLIT void -runtime·chanrecv2(ChanType *t, Hchan* c, ...) +runtime·chanrecv2(ChanType *t, Hchan* c, byte *v, bool received) { - byte *ae, *ap; - - ae = (byte*)(&c+1); - ap = ae + t->elem->size; - runtime·chanrecv(t, c, ae, nil, ap); + runtime·chanrecv(t, c, v, nil, &received); } -// func selectnbsend(c chan any, elem any) bool +// func selectnbsend(c chan any, elem *any) bool // // compiler implements // @@ -479,13 +475,9 @@ runtime·chanrecv2(ChanType *t, Hchan* c, ...) // #pragma textflag NOSPLIT void -runtime·selectnbsend(ChanType *t, Hchan *c, ...) +runtime·selectnbsend(ChanType *t, Hchan *c, byte *val, bool pres) { - byte *ae, *ap; - - ae = (byte*)(&c + 1); - ap = ae + ROUND(t->elem->size, Structrnd); - runtime·chansend(t, c, ae, ap, runtime·getcallerpc(&t)); + runtime·chansend(t, c, val, &pres, runtime·getcallerpc(&t)); } // func selectnbrecv(elem *any, c chan any) bool @@ -585,23 +577,19 @@ reflect·chanrecv(ChanType *t, Hchan *c, bool nb, byte *val, bool selected, bool runtime·chanrecv(t, c, val, sp, &received); } -static void newselect(int32, Select**); +static Select* newselect(int32); // newselect(size uint32) (sel *byte); #pragma textflag NOSPLIT void -runtime·newselect(int32 size, ...) +runtime·newselect(int32 size, byte *sel) { - int32 o; - Select **selp; - - o = ROUND(sizeof(size), Structrnd); - selp = (Select**)((byte*)&size + o); - newselect(size, selp); + sel = (byte*)newselect(size); + FLUSH(&sel); } -static void -newselect(int32 size, Select **selp) +static Select* +newselect(int32 size) { int32 n; Select *sel; @@ -623,10 +611,10 @@ newselect(int32 size, Select **selp) sel->ncase = 0; sel->lockorder = (void*)(sel->scase + size); sel->pollorder = (void*)(sel->lockorder + size); - *selp = sel; if(debug) runtime·printf("newselect s=%p size=%d\n", sel, size); + return sel; } // cut in half to give stack a chance to split @@ -1158,7 +1146,7 @@ reflect·rselect(Slice cases, intgo chosen, bool recvOK) rcase = (runtimeSelect*)cases.array; - newselect(cases.len, &sel); + sel = newselect(cases.len); for(i=0; idir) {