From 40af78c19eeceb38407c2b7c2a4d8b685249701f Mon Sep 17 00:00:00 2001 From: Luuk van Dijk Date: Sat, 2 Jun 2012 22:50:57 -0400 Subject: [PATCH] cmd/gc: inline slice[arr,str] in the frontend (mostly). R=rsc, ality, rogpeppe, minux.ma, dave CC=golang-dev https://golang.org/cl/5966075 --- src/cmd/5g/cgen.c | 21 ++ src/cmd/5g/gg.h | 1 - src/cmd/5g/ggen.c | 395 +----------------------------------- src/cmd/5g/gsubr.c | 21 ++ src/cmd/6g/cgen.c | 21 +- src/cmd/6g/gg.h | 1 - src/cmd/6g/ggen.c | 365 +-------------------------------- src/cmd/6g/gsubr.c | 19 ++ src/cmd/8g/cgen.c | 21 +- src/cmd/8g/gg.h | 1 - src/cmd/8g/ggen.c | 400 +------------------------------------ src/cmd/8g/gsubr.c | 19 ++ src/cmd/gc/builtin.c | 3 - src/cmd/gc/gen.c | 60 ++++++ src/cmd/gc/go.h | 2 + src/cmd/gc/runtime.go | 3 - src/cmd/gc/walk.c | 272 +++++++++++++++---------- src/pkg/runtime/slice.c | 143 ------------- src/pkg/runtime/string.goc | 25 --- 19 files changed, 354 insertions(+), 1439 deletions(-) diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index a1732d2320..2e13f9a6c9 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -30,6 +30,19 @@ cgen(Node *n, Node *res) if(res == N || res->type == T) fatal("cgen: res nil"); + switch(n->op) { + case OSLICE: + case OSLICEARR: + case OSLICESTR: + if (res->op != ONAME || !res->addable) { + tempname(&n1, n->type); + cgen_slice(n, &n1); + cgen(&n1, res); + } else + cgen_slice(n, res); + return; + } + while(n->op == OCONVNOP) n = n->left; @@ -577,6 +590,14 @@ agen(Node *n, Node *res) cgen_aret(n, res); break; + case OSLICE: + case OSLICEARR: + case OSLICESTR: + tempname(&n1, n->type); + cgen_slice(n, &n1); + agen(&n1, res); + break; + case OINDEX: p2 = nil; // to be patched to panicindex. w = n->type->width; diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h index a9e7ded683..d579ac16ce 100644 --- a/src/cmd/5g/gg.h +++ b/src/cmd/5g/gg.h @@ -78,7 +78,6 @@ void cgen_callinter(Node*, Node*, int); void cgen_proc(Node*, int); void cgen_callret(Node*, Node*); void cgen_dcl(Node*); -int cgen_inline(Node*, Node*); int needconvert(Type*, Type*); void genconv(Type*, Type*); void allocparams(void); diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 091ab77534..85f63a2f7a 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -68,8 +68,11 @@ ginscall(Node *f, int proc) break; case 0: // normal call + case -1: // normal call but no return p = gins(ABL, N, f); afunclit(&p->to); + if(proc == -1 || noreturn(p)) + gins(AUNDEF, N, N); break; case 1: // call in new proc (go) @@ -656,395 +659,3 @@ clearfat(Node *nl) regfree(&dst); regfree(&nz); } - -static int -regcmp(const void *va, const void *vb) -{ - Node *ra, *rb; - - ra = (Node*)va; - rb = (Node*)vb; - return ra->local - rb->local; -} - -static Prog* throwpc; - -// We're only going to bother inlining if we can -// convert all the arguments to 32 bits safely. Can we? -static int -fix64(NodeList *nn, int n) -{ - NodeList *l; - Node *r; - int i; - - l = nn; - for(i=0; in->right; - if(is64(r->type) && !smallintconst(r)) { - if(r->op == OCONV) - r = r->left; - if(is64(r->type)) - return 0; - } - l = l->next; - } - return 1; -} - -void -getargs(NodeList *nn, Node *reg, int n) -{ - NodeList *l; - int i; - - throwpc = nil; - - l = nn; - for(i=0; in->right) && !isslice(l->n->right->type)) { - regalloc(reg+i, l->n->right->type, N); - cgen(l->n->right, reg+i); - } else - reg[i] = *l->n->right; - if(reg[i].local != 0) - yyerror("local used"); - reg[i].local = l->n->left->xoffset; - l = l->next; - } - qsort((void*)reg, n, sizeof(*reg), regcmp); - for(i=0; ival.u.xval); - if(cl == 0) - return; - if(smallintconst(nr)) - return; - - // put the constant on the right - op = brrev(op); - c = nl; - nl = nr; - nr = c; - } - - n1.op = OXXX; - if(nr->op != OREGISTER) { - regalloc(&n1, types[TUINT32], N); - gmove(nr, &n1); - nr = &n1; - } - n2.op = OXXX; - if(nl->op != OREGISTER) { - regalloc(&n2, types[TUINT32], N); - gmove(nl, &n2); - nl = &n2; - } - gcmp(optoas(OCMP, types[TUINT32]), nl, nr); - if(nr == &n1) - regfree(&n1); - if(nl == &n2) - regfree(&n2); - if(throwpc == nil) { - p1 = gbranch(optoas(op, types[TUINT32]), T, +1); - throwpc = pc; - ginscall(panicslice, 0); - patch(p1, pc); - } else { - op = brcom(op); - p1 = gbranch(optoas(op, types[TUINT32]), T, -1); - patch(p1, throwpc); - } -} - -int -sleasy(Node *n) -{ - if(n->op != ONAME) - return 0; - if(!n->addable) - return 0; - return 1; -} - -// generate inline code for -// slicearray -// sliceslice -// arraytoslice -int -cgen_inline(Node *n, Node *res) -{ - Node nodes[5]; - Node n1, n2, n3, nres, ntemp; - vlong v; - int i, narg; - - if(n->op != OCALLFUNC) - goto no; - if(!n->left->addable) - goto no; - if(n->left->sym == S) - goto no; - if(n->left->sym->pkg != runtimepkg) - goto no; - if(strcmp(n->left->sym->name, "slicearray") == 0) - goto slicearray; - if(strcmp(n->left->sym->name, "sliceslice") == 0) { - narg = 4; - goto sliceslice; - } - if(strcmp(n->left->sym->name, "sliceslice1") == 0) { - narg = 3; - goto sliceslice; - } - goto no; - -slicearray: - if(!sleasy(res)) - goto no; - if(!fix64(n->list, 5)) - goto no; - getargs(n->list, nodes, 5); - - // if(hb[3] > nel[1]) goto throw - cmpandthrow(&nodes[3], &nodes[1]); - - // if(lb[2] > hb[3]) goto throw - cmpandthrow(&nodes[2], &nodes[3]); - - // len = hb[3] - lb[2] (destroys hb) - n2 = *res; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - - if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[3].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gmove(&n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[3]); - gmove(&nodes[3], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gmove(&n1, &n2); - regfree(&n1); - } - - // cap = nel[1] - lb[2] (destroys nel) - n2 = *res; - n2.type = types[TUINT32]; - n2.xoffset += Array_cap; - - if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[1].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gmove(&n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[1]); - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gmove(&n1, &n2); - regfree(&n1); - } - - // if slice could be too big, dereference to - // catch nil array pointer. - if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) { - n2 = nodes[0]; - n2.xoffset = 0; - n2.op = OINDREG; - n2.type = types[TUINT8]; - regalloc(&n1, types[TUINT32], N); - gins(AMOVB, &n2, &n1); - regfree(&n1); - } - - // ary = old[0] + (lb[2] * width[4]) (destroys old) - n2 = *res; - n2.type = types[tptr]; - n2.xoffset += Array_array; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) { - v = mpgetfix(nodes[2].val.u.xval) * - mpgetfix(nodes[4].val.u.xval); - if(v != 0) { - nodconst(&n1, types[tptr], v); - gins(optoas(OADD, types[tptr]), &n1, &nodes[0]); - } - } else { - regalloc(&n1, types[tptr], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) { - regalloc(&n3, types[tptr], N); - gmove(&nodes[4], &n3); - gins(optoas(OMUL, types[tptr]), &n3, &n1); - regfree(&n3); - } - gins(optoas(OADD, types[tptr]), &n1, &nodes[0]); - regfree(&n1); - } - gmove(&nodes[0], &n2); - - for(i=0; i<5; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - return 1; - -sliceslice: - if(!fix64(n->list, narg)) - goto no; - ntemp.op = OXXX; - if(!sleasy(n->list->n->right)) { - Node *n0; - - n0 = n->list->n->right; - tempname(&ntemp, res->type); - cgen(n0, &ntemp); - n->list->n->right = &ntemp; - getargs(n->list, nodes, narg); - n->list->n->right = n0; - } else - getargs(n->list, nodes, narg); - - nres = *res; // result - if(!sleasy(res)) { - if(ntemp.op == OXXX) - tempname(&ntemp, res->type); - nres = ntemp; - } - - if(narg == 3) { // old[lb:] - // move width to where it would be for old[lb:hb] - nodes[3] = nodes[2]; - nodes[2].op = OXXX; - - // if(lb[1] > old.nel[0]) goto throw; - n2 = nodes[0]; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - cmpandthrow(&nodes[1], &n2); - - // ret.nel = old.nel[0]-lb[1]; - n2 = nodes[0]; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - - regalloc(&n1, types[TUINT32], N); - gmove(&n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - gmove(&n1, &n2); - regfree(&n1); - } else { // old[lb:hb] - // if(hb[2] > old.cap[0]) goto throw; - n2 = nodes[0]; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - cmpandthrow(&nodes[2], &n2); - - // if(lb[1] > hb[2]) goto throw; - cmpandthrow(&nodes[1], &nodes[2]); - - // ret.len = hb[2]-lb[1]; (destroys hb[2]) - n2 = nres; - n2.type = types[TUINT32]; - n2.xoffset += Array_nel; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) { - v = mpgetfix(nodes[2].val.u.xval) - - mpgetfix(nodes[1].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gmove(&n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - gmove(&n1, &n2); - regfree(&n1); - } - } - - // ret.cap = old.cap[0]-lb[1]; (uses hb[2]) - n2 = nodes[0]; - n2.type = types[TUINT32]; - n2.xoffset += Array_cap; - - regalloc(&n1, types[TUINT32], &nodes[2]); - gmove(&n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.type = types[TUINT32]; - n2.xoffset += Array_cap; - gmove(&n1, &n2); - regfree(&n1); - - // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1]) - n2 = nodes[0]; - n2.type = types[tptr]; - n2.xoffset += Array_array; - regalloc(&n3, types[tptr], N); - gmove(&n2, &n3); - - regalloc(&n1, types[tptr], &nodes[1]); - if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) { - gmove(&n2, &n1); - v = mpgetfix(nodes[1].val.u.xval) * - mpgetfix(nodes[3].val.u.xval); - if(v != 0) { - nodconst(&n2, types[tptr], v); - gins(optoas(OADD, types[tptr]), &n3, &n1); - } - } else { - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) { - regalloc(&n2, types[tptr], N); - gmove(&nodes[3], &n2); - gins(optoas(OMUL, types[tptr]), &n2, &n1); - regfree(&n2); - } - gins(optoas(OADD, types[tptr]), &n3, &n1); - } - regfree(&n3); - - n2 = nres; - n2.type = types[tptr]; - n2.xoffset += Array_array; - gmove(&n1, &n2); - regfree(&n1); - - for(i=0; i<4; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - - if(!sleasy(res)) { - cgen(&nres, res); - } - return 1; - -no: - return 0; -} diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index e4899fc91f..74266cb15f 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -1141,6 +1141,27 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs) return p; } +// Generate an instruction referencing *n +// to force segv on nil pointer dereference. +bsdvoid +checkref(Node *n) +{ + Node m1, m2; + + if(n->type->type->width < unmappedzero) + return; + + regalloc(&m1, types[TUINTPTR], n); + regalloc(&m2, types[TUINT8], n); + cgen(n, &m1); + m1.xoffset = 0; + m1.op = OINDREG; + m1.type = types[TUINT8]; + gins(AMOVBU, &m1, &m2); + regfree(&m2); + regfree(&m1); +} + static void checkoffset(Addr *a, int canemitcode) { diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index 249fcd71a0..e38fb86a32 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -33,9 +33,18 @@ cgen(Node *n, Node *res) while(n->op == OCONVNOP) n = n->left; - // inline slices - if(cgen_inline(n, res)) + switch(n->op) { + case OSLICE: + case OSLICEARR: + case OSLICESTR: + if (res->op != ONAME || !res->addable) { + tempname(&n1, n->type); + cgen_slice(n, &n1); + cgen(&n1, res); + } else + cgen_slice(n, res); goto ret; + } if(n->ullman >= UINF) { if(n->op == OINDREG) @@ -532,6 +541,14 @@ agen(Node *n, Node *res) cgen_aret(n, res); break; + case OSLICE: + case OSLICEARR: + case OSLICESTR: + tempname(&n1, n->type); + cgen_slice(n, &n1); + agen(&n1, res); + break; + case OINDEX: w = n->type->width; if(nr->addable) diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index 2e2ee498f3..4073e228c6 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -92,7 +92,6 @@ Prog* gins(int, Node*, Node*); int samaddr(Node*, Node*); void naddr(Node*, Addr*, int); void cgen_aret(Node*, Node*); -int cgen_inline(Node*, Node*); void restx(Node*, Node*); void savex(int, Node*, Node*, Node*, Type*); int componentgen(Node*, Node*); diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index de5e818429..4d9fa4812f 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -69,7 +69,7 @@ ginscall(Node *f, int proc) case -1: // normal call but no return p = gins(ACALL, N, f); afunclit(&p->to); - if(proc == -1) + if(proc == -1 || noreturn(p)) gins(AUNDEF, N, N); break; @@ -1068,366 +1068,3 @@ clearfat(Node *nl) restx(&n1, &oldn1); restx(&ax, &oldax); } - -static int -regcmp(const void *va, const void *vb) -{ - Node *ra, *rb; - - ra = (Node*)va; - rb = (Node*)vb; - return ra->local - rb->local; -} - -static Prog* throwpc; - -void -getargs(NodeList *nn, Node *reg, int n) -{ - NodeList *l; - int i; - - throwpc = nil; - - l = nn; - for(i=0; in->right) && !isslice(l->n->right->type)) { - regalloc(reg+i, l->n->right->type, N); - cgen(l->n->right, reg+i); - } else - reg[i] = *l->n->right; - if(reg[i].local != 0) - yyerror("local used"); - reg[i].local = l->n->left->xoffset; - l = l->next; - } - qsort((void*)reg, n, sizeof(*reg), regcmp); - for(i=0; iop == OCONV && is64(nl->type)) - nl = nl->left; - if(nr->op == OCONV && is64(nr->type)) - nr = nr->left; - - op = OLE; - if(smallintconst(nl)) { - cl = mpgetfix(nl->val.u.xval); - if(cl == 0) - return; - if(smallintconst(nr)) - return; - // put the constant on the right - op = brrev(op); - c = nl; - nl = nr; - nr = c; - } - if(is64(nr->type) && smallintconst(nr)) - nr->type = types[TUINT32]; - - n1.op = OXXX; - t = types[TUINT32]; - if(nl->type->width != t->width || nr->type->width != t->width) { - if((is64(nl->type) && nl->op != OLITERAL) || (is64(nr->type) && nr->op != OLITERAL)) - t = types[TUINT64]; - - // Check if we need to use a temporary. - // At least one of the arguments is 32 bits - // (the len or cap) so one temporary suffices. - if(nl->type->width != t->width && nl->op != OLITERAL) { - regalloc(&n1, t, nl); - gmove(nl, &n1); - nl = &n1; - } else if(nr->type->width != t->width && nr->op != OLITERAL) { - regalloc(&n1, t, nr); - gmove(nr, &n1); - nr = &n1; - } - } - gins(optoas(OCMP, t), nl, nr); - if(n1.op != OXXX) - regfree(&n1); - if(throwpc == nil) { - p1 = gbranch(optoas(op, t), T, +1); - throwpc = pc; - ginscall(panicslice, -1); - patch(p1, pc); - } else { - op = brcom(op); - p1 = gbranch(optoas(op, t), T, -1); - patch(p1, throwpc); - } -} - -int -sleasy(Node *n) -{ - if(n->op != ONAME) - return 0; - if(!n->addable) - return 0; - return 1; -} - -// generate inline code for -// slicearray -// sliceslice -// arraytoslice -int -cgen_inline(Node *n, Node *res) -{ - Node nodes[5]; - Node n1, n2, nres, ntemp; - vlong v; - int i, narg, nochk; - - if(n->op != OCALLFUNC) - goto no; - if(!n->left->addable) - goto no; - if(n->left->sym == S) - goto no; - if(n->left->sym->pkg != runtimepkg) - goto no; - if(strcmp(n->left->sym->name, "slicearray") == 0) - goto slicearray; - if(strcmp(n->left->sym->name, "sliceslice") == 0) { - narg = 4; - goto sliceslice; - } - if(strcmp(n->left->sym->name, "sliceslice1") == 0) { - narg = 3; - goto sliceslice; - } - goto no; - -slicearray: - if(!sleasy(res)) - goto no; - getargs(n->list, nodes, 5); - - // if(hb[3] > nel[1]) goto throw - cmpandthrow(&nodes[3], &nodes[1]); - - // if(lb[2] > hb[3]) goto throw - cmpandthrow(&nodes[2], &nodes[3]); - - // len = hb[3] - lb[2] (destroys hb) - n2 = *res; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - - if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[3].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[3]); - gmove(&nodes[3], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } - - // cap = nel[1] - lb[2] (destroys nel) - n2 = *res; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - - if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[1].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[1]); - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } - - // if slice could be too big, dereference to - // catch nil array pointer. - if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) { - n2 = nodes[0]; - n2.xoffset = 0; - n2.op = OINDREG; - n2.type = types[TUINT8]; - gins(ATESTB, nodintconst(0), &n2); - } - - // ary = old[0] + (lb[2] * width[4]) (destroys old) - n2 = *res; - n2.xoffset += Array_array; - n2.type = types[tptr]; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) { - v = mpgetfix(nodes[2].val.u.xval) * - mpgetfix(nodes[4].val.u.xval); - if(v != 0) - ginscon(optoas(OADD, types[tptr]), v, &nodes[0]); - } else { - regalloc(&n1, types[tptr], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) - gins(optoas(OMUL, types[tptr]), &nodes[4], &n1); - gins(optoas(OADD, types[tptr]), &n1, &nodes[0]); - regfree(&n1); - } - gins(optoas(OAS, types[tptr]), &nodes[0], &n2); - - for(i=0; i<5; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - return 1; - -sliceslice: - nochk = n->etype; // skip bounds checking - ntemp.op = OXXX; - if(!sleasy(n->list->n->right)) { - Node *n0; - - n0 = n->list->n->right; - tempname(&ntemp, res->type); - cgen(n0, &ntemp); - n->list->n->right = &ntemp; - getargs(n->list, nodes, narg); - n->list->n->right = n0; - } else - getargs(n->list, nodes, narg); - - nres = *res; // result - if(!sleasy(res)) { - if(ntemp.op == OXXX) - tempname(&ntemp, res->type); - nres = ntemp; - } - - if(narg == 3) { // old[lb:] - // move width to where it would be for old[lb:hb] - nodes[3] = nodes[2]; - nodes[2].op = OXXX; - - // if(lb[1] > old.nel[0]) goto throw; - n2 = nodes[0]; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - if(!nochk) - cmpandthrow(&nodes[1], &n2); - - // ret.nel = old.nel[0]-lb[1]; - n2 = nodes[0]; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - - regalloc(&n1, types[TUINT32], N); - gins(optoas(OAS, types[TUINT32]), &n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } else { // old[lb:hb] - n2 = nodes[0]; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - if(!nochk) { - // if(hb[2] > old.cap[0]) goto throw; - cmpandthrow(&nodes[2], &n2); - // if(lb[1] > hb[2]) goto throw; - cmpandthrow(&nodes[1], &nodes[2]); - } - // ret.len = hb[2]-lb[1]; (destroys hb[2]) - n2 = nres; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) { - v = mpgetfix(nodes[2].val.u.xval) - - mpgetfix(nodes[1].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } - } - - // ret.cap = old.cap[0]-lb[1]; (uses hb[2]) - n2 = nodes[0]; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - - regalloc(&n1, types[TUINT32], &nodes[2]); - gins(optoas(OAS, types[TUINT32]), &n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - - // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1]) - n2 = nodes[0]; - n2.xoffset += Array_array; - n2.type = types[tptr]; - regalloc(&n1, types[tptr], &nodes[1]); - if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) { - gins(optoas(OAS, types[tptr]), &n2, &n1); - v = mpgetfix(nodes[1].val.u.xval) * - mpgetfix(nodes[3].val.u.xval); - if(v != 0) - ginscon(optoas(OADD, types[tptr]), v, &n1); - } else { - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) - gins(optoas(OMUL, types[tptr]), &nodes[3], &n1); - gins(optoas(OADD, types[tptr]), &n2, &n1); - } - - n2 = nres; - n2.xoffset += Array_array; - n2.type = types[tptr]; - gins(optoas(OAS, types[tptr]), &n1, &n2); - regfree(&n1); - - for(i=0; i<4; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - - if(!sleasy(res)) { - cgen(&nres, res); - } - return 1; - -no: - return 0; -} diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index d286bca2fe..8284bd3da5 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -1029,6 +1029,25 @@ gins(int as, Node *f, Node *t) return p; } +// Generate an instruction referencing *n +// to force segv on nil pointer dereference. +void +checkref(Node *n) +{ + Node m; + + if(n->type->type->width < unmappedzero) + return; + + regalloc(&m, types[TUINTPTR], n); + cgen(n, &m); + m.xoffset = 0; + m.op = OINDREG; + m.type = types[TUINT8]; + gins(ATESTB, nodintconst(0), &m); + regfree(&m); +} + static void checkoffset(Addr *a, int canemitcode) { diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index 8f6bfc24d0..860e8cb6c0 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -63,9 +63,18 @@ cgen(Node *n, Node *res) if(res == N || res->type == T) fatal("cgen: res nil"); - // inline slices - if(cgen_inline(n, res)) + switch(n->op) { + case OSLICE: + case OSLICEARR: + case OSLICESTR: + if (res->op != ONAME || !res->addable) { + tempname(&n1, n->type); + cgen_slice(n, &n1); + cgen(&n1, res); + } else + cgen_slice(n, res); return; + } while(n->op == OCONVNOP) n = n->left; @@ -532,6 +541,14 @@ agen(Node *n, Node *res) cgen_aret(n, res); break; + case OSLICE: + case OSLICEARR: + case OSLICESTR: + tempname(&n1, n->type); + cgen_slice(n, &n1); + agen(&n1, res); + break; + case OINDEX: p2 = nil; // to be patched to panicindex. w = n->type->width; diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h index 0edb54c178..12632f651c 100644 --- a/src/cmd/8g/gg.h +++ b/src/cmd/8g/gg.h @@ -104,7 +104,6 @@ Prog* gins(int, Node*, Node*); int samaddr(Node*, Node*); void naddr(Node*, Addr*, int); void cgen_aret(Node*, Node*); -int cgen_inline(Node*, Node*); Node* ncon(uint32); void mgen(Node*, Node*, Node*); void mfree(Node*); diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index b113788ef7..749f913ef5 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -109,7 +109,7 @@ ginscall(Node *f, int proc) case -1: // normal call but no return p = gins(ACALL, N, f); afunclit(&p->to); - if(proc == -1) + if(proc == -1 || noreturn(p)) gins(AUNDEF, N, N); break; @@ -780,401 +780,3 @@ cgen_bmul(int op, Node *nl, Node *nr, Node *res) regfree(&n1b); regfree(&n2b); } - -static int -regcmp(const void *va, const void *vb) -{ - Node *ra, *rb; - - ra = (Node*)va; - rb = (Node*)vb; - return ra->local - rb->local; -} - -static Prog* throwpc; - -// We're only going to bother inlining if we can -// convert all the arguments to 32 bits safely. Can we? -static int -fix64(NodeList *nn, int n) -{ - NodeList *l; - Node *r; - int i; - - l = nn; - for(i=0; in->right; - if(is64(r->type) && !smallintconst(r)) { - if(r->op == OCONV) - r = r->left; - if(is64(r->type)) - return 0; - } - l = l->next; - } - return 1; -} - -void -getargs(NodeList *nn, Node *reg, int n) -{ - NodeList *l; - Node *r; - int i; - - throwpc = nil; - - l = nn; - for(i=0; in->right; - if(is64(r->type)) { - if(r->op == OCONV) - r = r->left; - else if(smallintconst(r)) - r->type = types[TUINT32]; - if(is64(r->type)) - fatal("getargs"); - } - if(!smallintconst(r) && !isslice(r->type)) { - if(i < 3) // AX CX DX - nodreg(reg+i, r->type, D_AX+i); - else - reg[i].op = OXXX; - regalloc(reg+i, r->type, reg+i); - cgen(r, reg+i); - } else - reg[i] = *r; - if(reg[i].local != 0) - yyerror("local used"); - reg[i].local = l->n->left->xoffset; - l = l->next; - } - qsort((void*)reg, n, sizeof(*reg), regcmp); - for(i=0; ival.u.xval); - if(cl == 0) - return; - if(smallintconst(nr)) - return; - // put the constant on the right - op = brrev(op); - c = nl; - nl = nr; - nr = c; - } - - // Arguments are known not to be 64-bit, - // but they might be smaller than 32 bits. - // Check if we need to use a temporary. - // At least one of the arguments is 32 bits - // (the len or cap) so one temporary suffices. - n1.op = OXXX; - t = types[TUINT32]; - if(nl->type->width != t->width) { - regalloc(&n1, t, nl); - gmove(nl, &n1); - nl = &n1; - } else if(nr->type->width != t->width) { - regalloc(&n1, t, nr); - gmove(nr, &n1); - nr = &n1; - } - gins(optoas(OCMP, t), nl, nr); - if(n1.op != OXXX) - regfree(&n1); - if(throwpc == nil) { - p1 = gbranch(optoas(op, t), T, +1); - throwpc = pc; - ginscall(panicslice, -1); - patch(p1, pc); - } else { - op = brcom(op); - p1 = gbranch(optoas(op, t), T, -1); - patch(p1, throwpc); - } -} - -int -sleasy(Node *n) -{ - if(n->op != ONAME) - return 0; - if(!n->addable) - return 0; - return 1; -} - -// generate inline code for -// slicearray -// sliceslice -// arraytoslice -int -cgen_inline(Node *n, Node *res) -{ - Node nodes[5]; - Node n1, n2, nres, ntemp; - vlong v; - int i, narg, nochk; - - if(n->op != OCALLFUNC) - goto no; - if(!n->left->addable) - goto no; - if(n->left->sym == S) - goto no; - if(n->left->sym->pkg != runtimepkg) - goto no; - if(strcmp(n->left->sym->name, "slicearray") == 0) - goto slicearray; - if(strcmp(n->left->sym->name, "sliceslice") == 0) { - narg = 4; - goto sliceslice; - } - if(strcmp(n->left->sym->name, "sliceslice1") == 0) { - narg = 3; - goto sliceslice; - } - goto no; - -slicearray: - if(!sleasy(res)) - goto no; - if(!fix64(n->list, 5)) - goto no; - getargs(n->list, nodes, 5); - - // if(hb[3] > nel[1]) goto throw - cmpandthrow(&nodes[3], &nodes[1]); - - // if(lb[2] > hb[3]) goto throw - cmpandthrow(&nodes[2], &nodes[3]); - - // len = hb[3] - lb[2] (destroys hb) - n2 = *res; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - - if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[3].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[3]); - gmove(&nodes[3], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } - - // cap = nel[1] - lb[2] (destroys nel) - n2 = *res; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - - if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) { - v = mpgetfix(nodes[1].val.u.xval) - - mpgetfix(nodes[2].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[1]); - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[2]) || mpgetfix(nodes[2].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[2], &n1); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } - - // if slice could be too big, dereference to - // catch nil array pointer. - if(nodes[0].op == OREGISTER && nodes[0].type->type->width >= unmappedzero) { - n2 = nodes[0]; - n2.xoffset = 0; - n2.op = OINDREG; - n2.type = types[TUINT8]; - gins(ATESTB, nodintconst(0), &n2); - } - - // ary = old[0] + (lb[2] * width[4]) (destroys old) - n2 = *res; - n2.xoffset += Array_array; - n2.type = types[tptr]; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) { - v = mpgetfix(nodes[2].val.u.xval) * - mpgetfix(nodes[4].val.u.xval); - if(v != 0) { - nodconst(&n1, types[tptr], v); - gins(optoas(OADD, types[tptr]), &n1, &nodes[0]); - } - } else { - regalloc(&n1, types[tptr], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[4]) || mpgetfix(nodes[4].val.u.xval) != 1) - gins(optoas(OMUL, types[tptr]), &nodes[4], &n1); - gins(optoas(OADD, types[tptr]), &n1, &nodes[0]); - regfree(&n1); - } - gins(optoas(OAS, types[tptr]), &nodes[0], &n2); - - for(i=0; i<5; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - return 1; - -sliceslice: - if(!fix64(n->list, narg)) - goto no; - nochk = n->etype; // skip bounds checking - ntemp.op = OXXX; - if(!sleasy(n->list->n->right)) { - Node *n0; - - n0 = n->list->n->right; - tempname(&ntemp, res->type); - cgen(n0, &ntemp); - n->list->n->right = &ntemp; - getargs(n->list, nodes, narg); - n->list->n->right = n0; - } else - getargs(n->list, nodes, narg); - - nres = *res; // result - if(!sleasy(res)) { - if(ntemp.op == OXXX) - tempname(&ntemp, res->type); - nres = ntemp; - } - - if(narg == 3) { // old[lb:] - // move width to where it would be for old[lb:hb] - nodes[3] = nodes[2]; - nodes[2].op = OXXX; - - // if(lb[1] > old.nel[0]) goto throw; - n2 = nodes[0]; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - if(!nochk) - cmpandthrow(&nodes[1], &n2); - - // ret.nel = old.nel[0]-lb[1]; - n2 = nodes[0]; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - - regalloc(&n1, types[TUINT32], N); - gins(optoas(OAS, types[TUINT32]), &n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } else { // old[lb:hb] - n2 = nodes[0]; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - if (!nochk) { - // if(hb[2] > old.cap[0]) goto throw; - cmpandthrow(&nodes[2], &n2); - // if(lb[1] > hb[2]) goto throw; - cmpandthrow(&nodes[1], &nodes[2]); - } - - // ret.len = hb[2]-lb[1]; (destroys hb[2]) - n2 = nres; - n2.xoffset += Array_nel; - n2.type = types[TUINT32]; - - if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) { - v = mpgetfix(nodes[2].val.u.xval) - - mpgetfix(nodes[1].val.u.xval); - nodconst(&n1, types[TUINT32], v); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - } else { - regalloc(&n1, types[TUINT32], &nodes[2]); - gmove(&nodes[2], &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - } - } - - // ret.cap = old.cap[0]-lb[1]; (uses hb[2]) - n2 = nodes[0]; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - - regalloc(&n1, types[TUINT32], &nodes[2]); - gins(optoas(OAS, types[TUINT32]), &n2, &n1); - if(!smallintconst(&nodes[1]) || mpgetfix(nodes[1].val.u.xval) != 0) - gins(optoas(OSUB, types[TUINT32]), &nodes[1], &n1); - - n2 = nres; - n2.xoffset += Array_cap; - n2.type = types[TUINT32]; - gins(optoas(OAS, types[TUINT32]), &n1, &n2); - regfree(&n1); - - // ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1]) - n2 = nodes[0]; - n2.xoffset += Array_array; - n2.type = types[tptr]; - - regalloc(&n1, types[tptr], &nodes[1]); - if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) { - gins(optoas(OAS, types[tptr]), &n2, &n1); - v = mpgetfix(nodes[1].val.u.xval) * - mpgetfix(nodes[3].val.u.xval); - if(v != 0) { - nodconst(&n2, types[tptr], v); - gins(optoas(OADD, types[tptr]), &n2, &n1); - } - } else { - gmove(&nodes[1], &n1); - if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1) - gins(optoas(OMUL, types[tptr]), &nodes[3], &n1); - gins(optoas(OADD, types[tptr]), &n2, &n1); - } - - n2 = nres; - n2.xoffset += Array_array; - n2.type = types[tptr]; - gins(optoas(OAS, types[tptr]), &n1, &n2); - regfree(&n1); - - for(i=0; i<4; i++) { - if(nodes[i].op == OREGISTER) - regfree(&nodes[i]); - } - - if(!sleasy(res)) { - cgen(&nres, res); - } - return 1; - -no: - return 0; -} diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c index 9d504c6791..4011fa5c59 100644 --- a/src/cmd/8g/gsubr.c +++ b/src/cmd/8g/gsubr.c @@ -1768,6 +1768,25 @@ gins(int as, Node *f, Node *t) return p; } +// Generate an instruction referencing *n +// to force segv on nil pointer dereference. +void +checkref(Node *n) +{ + Node m; + + if(n->type->type->width < unmappedzero) + return; + + regalloc(&m, types[TUINTPTR], n); + cgen(n, &m); + m.xoffset = 0; + m.op = OINDREG; + m.type = types[TUINT8]; + gins(ATESTB, nodintconst(0), &m); + regfree(&m); +} + static void checkoffset(Addr *a, int canemitcode) { diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c index ca3d6670d4..4aec0c04ea 100644 --- a/src/cmd/gc/builtin.c +++ b/src/cmd/gc/builtin.c @@ -86,9 +86,6 @@ char *runtimeimport = "func @\"\".block()\n" "func @\"\".makeslice(@\"\".typ *byte, @\"\".nel int64, @\"\".cap int64) (@\"\".ary []any)\n" "func @\"\".growslice(@\"\".typ *byte, @\"\".old []any, @\"\".n int64) (@\"\".ary []any)\n" - "func @\"\".sliceslice1(@\"\".old []any, @\"\".lb uint64, @\"\".width uint64) (@\"\".ary []any)\n" - "func @\"\".sliceslice(@\"\".old []any, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n" - "func @\"\".slicearray(@\"\".old *any, @\"\".nel uint64, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n" "func @\"\".closure()\n" "func @\"\".memequal(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" "func @\"\".memequal8(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 5012e4a52d..9806600277 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -734,6 +734,66 @@ ret: ; } + +/* + * generate: + * res = s[lo, hi]; + * n->left is s + * n->list is (cap(s)-lo(TUINT32), hi-lo(TUINT32)[, lo*width(TUINTPTR)]) + * caller (cgen) guarantees res is an addable ONAME. + * + */ +void +cgen_slice(Node *n, Node *res) +{ + Node src, dst, *cap, *len, *offs, *add; + +// print("cgen_slice: %N = %+N\n", res, n); + + cap = n->list->n; + len = n->list->next->n; + offs = N; + if(n->list->next->next) + offs = n->list->next->next->n; + + // dst.len = hi [ - lo ] + dst = *res; + dst.xoffset += Array_nel; + dst.type = types[TUINT32]; + cgen(len, &dst); + + if(n->op != OSLICESTR) { + // dst.cap = cap [ - lo ] + dst = *res; + dst.xoffset += Array_cap; + dst.type = types[TUINT32]; + cgen(cap, &dst); + } + + // dst.array = src.array [ + lo *width ] + dst = *res; + dst.xoffset += Array_array; + dst.type = types[TUINTPTR]; + + if(n->op == OSLICEARR) { + if(!isptr[n->left->type->etype]) + fatal("slicearr is supposed to work on pointer: %+N\n", n); + checkref(n->left); + } + + src = *n->left; + src.xoffset += Array_array; + src.type = types[TUINTPTR]; + + if(offs == N) { + cgen(&src, &dst); + } else { + add = nod(OADD, &src, offs); + typecheck(&add, Erv); + cgen(add, &dst); + } +} + /* * gather series of offsets * >=0 is direct addressed field diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 71268aa6f7..82fe05be5d 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -987,6 +987,7 @@ void dumplist(char *s, NodeList *l); void addrescapes(Node *n); void cgen_as(Node *nl, Node *nr); void cgen_callmeth(Node *n, int proc); +void cgen_slice(Node* n, Node* res); void clearlabels(void); void checklabels(void); int dotoffset(Node *n, int *oary, Node **nn); @@ -1305,6 +1306,7 @@ EXTERN Node* nodfp; int anyregalloc(void); void betypeinit(void); void bgen(Node *n, int true, int likely, Prog *to); +void checkref(Node*); void cgen(Node*, Node*); void cgen_asop(Node *n); void cgen_call(Node *n, int proc); diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 15a61d9ef6..d5cdb2a5ea 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -117,9 +117,6 @@ func block() func makeslice(typ *byte, nel int64, cap int64) (ary []any) func growslice(typ *byte, old []any, n int64) (ary []any) -func sliceslice1(old []any, lb uint64, width uint64) (ary []any) -func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) -func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any) func closure() // has args, but compiler fills in diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 026db25edd..262135bcbe 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -21,6 +21,7 @@ static NodeList* reorder3(NodeList*); static Node* addstr(Node*, NodeList**); static Node* appendslice(Node*, NodeList**); static Node* append(Node*, NodeList**); +static Node* sliceany(Node*, NodeList**); static void walkcompare(Node**, NodeList**); static void walkrotate(Node**); static int bounded(Node*, int64); @@ -371,7 +372,7 @@ walkexpr(Node **np, NodeList **init) NodeList *ll, *lr, *lpost; Type *t; int et; - int64 v, v1, v2, len; + int64 v; int32 lno; Node *n, *fn; char buf[100], *p; @@ -916,95 +917,29 @@ walkexpr(Node **np, NodeList **init) goto ret; case OSLICE: + if(n->right != N && n->right->left == N && n->right->right == N) { // noop + walkexpr(&n->left, init); + n = n->left; + goto ret; + } + // fallthrough case OSLICEARR: + case OSLICESTR: + if(n->right == N) // already processed + goto ret; + walkexpr(&n->left, init); - n->left = safeexpr(n->left, init); + // cgen_slice can't handle string literals as source + // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi] + if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX)) + n->left = copyexpr(n->left, n->left->type, init); + else + n->left = safeexpr(n->left, init); walkexpr(&n->right->left, init); n->right->left = safeexpr(n->right->left, init); walkexpr(&n->right->right, init); n->right->right = safeexpr(n->right->right, init); - - len = 1LL<<60; - t = n->left->type; - if(t != T && isptr[t->etype]) - t = t->type; - if(isfixedarray(t)) - len = t->bound; - - // check for static out of bounds - // NOTE: v > len not v >= len. - v1 = -1; - v2 = -1; - if(isconst(n->right->left, CTINT)) { - v1 = mpgetfix(n->right->left->val.u.xval); - if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) { - yyerror("slice index out of bounds"); - v1 = -1; - } - } - if(isconst(n->right->right, CTINT)) { - v2 = mpgetfix(n->right->right->val.u.xval); - if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) { - yyerror("slice index out of bounds"); - v2 = -1; - } - } - if(v1 >= 0 && v2 >= 0 && v1 > v2) - yyerror("inverted slice range"); - - if(n->op == OSLICEARR) - goto slicearray; - - // dynamic slice - // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) - // sliceslice1(old []any, lb uint64, width uint64) (ary []any) - t = n->type; - et = n->bounded; - if(n->right->left == N) - l = nodintconst(0); - else - l = conv(n->right->left, types[TUINT64]); - if(n->right->right != N) { - fn = syslook("sliceslice", 1); - argtype(fn, t->type); // any-1 - argtype(fn, t->type); // any-2 - n = mkcall1(fn, t, init, - n->left, - l, - conv(n->right->right, types[TUINT64]), - nodintconst(t->type->width)); - } else { - fn = syslook("sliceslice1", 1); - argtype(fn, t->type); // any-1 - argtype(fn, t->type); // any-2 - n = mkcall1(fn, t, init, - n->left, - l, - nodintconst(t->type->width)); - } - n->bounded = et; // preserve flag from OSLICE to the slice* call. - goto ret; - - slicearray: - // static slice - // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any) - t = n->type; - fn = syslook("slicearray", 1); - argtype(fn, n->left->type->type); // any-1 - argtype(fn, t->type); // any-2 - if(n->right->left == N) - l = nodintconst(0); - else - l = conv(n->right->left, types[TUINT64]); - if(n->right->right == N) - r = nodintconst(n->left->type->type->bound); - else - r = conv(n->right->right, types[TUINT64]); - n = mkcall1(fn, t, init, - n->left, nodintconst(n->left->type->type->bound), - l, - r, - nodintconst(t->type->width)); + n = sliceany(n, init); // chops n->right, sets n->list goto ret; case OADDR: @@ -1082,25 +1017,7 @@ walkexpr(Node **np, NodeList **init) case OADDSTR: n = addstr(n, init); goto ret; - - case OSLICESTR: - // sys_slicestring(s, lb, hb) - if(n->right->left == N) - l = nodintconst(0); - else - l = conv(n->right->left, types[TINT]); - if(n->right->right) { - n = mkcall("slicestring", n->type, init, - conv(n->left, types[TSTRING]), - l, - conv(n->right->right, types[TINT])); - } else { - n = mkcall("slicestring1", n->type, init, - conv(n->left, types[TSTRING]), - l); - } - goto ret; - + case OAPPEND: if(n->isddd) { if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING)) @@ -2433,6 +2350,155 @@ append(Node *n, NodeList **init) return ns; } + +// Generate frontend part for OSLICE[ARR|STR] +// +static Node* +sliceany(Node* n, NodeList **init) +{ + int bounded; + Node *src, *lb, *hb, *bound, *chk, *chk1, *chk2; + int64 lbv, hbv, bv, w; + Type *bt; + +// print("before sliceany: %+N\n", n); + + src = n->left; + lb = n->right->left; + hb = n->right->right; + + bounded = n->etype; + + if(n->op == OSLICESTR) + bound = nod(OLEN, src, N); + else + bound = nod(OCAP, src, N); + + typecheck(&bound, Erv); + walkexpr(&bound, init); // if src is an array, bound will be a const now. + + // static checks if possible + bv = 1LL<<50; + if(isconst(bound, CTINT)) { + if(!smallintconst(bound)) + yyerror("array len too large"); + else + bv = mpgetfix(bound->val.u.xval); + } + lbv = -1; + hbv = -1; + + if(isconst(hb, CTINT)) { + hbv = mpgetfix(hb->val.u.xval); + if(hbv < 0 || hbv > bv || !smallintconst(hb)) { + yyerror("slice index out of bounds"); + hbv = -1; + } + } + if(isconst(lb, CTINT)) { + lbv = mpgetfix(lb->val.u.xval); + if(lbv < 0 || lbv > bv || !smallintconst(lb)) { + yyerror("slice index out of bounds"); + lbv = -1; + } + if(lbv == 0) + lb = N; + } + if(lbv >= 0 && hbv >= 0 && lbv > hbv) + yyerror("inverted slice range"); + + // dynamic checks convert all bounds to unsigned to save us the bound < 0 comparison + // generate + // if hb > bound || lb > hb { panicslice() } + chk = N; + chk1 = N; + chk2 = N; + + bt = types[TUINT32]; + if(hb != N && hb->type->width > 4) + bt = types[TUINT64]; + if(lb != N && lb->type->width > 4) + bt = types[TUINT64]; + + bound = cheapexpr(conv(bound, bt), init); + + if(hb != N) { + hb = cheapexpr(conv(hb, bt), init); + if(!bounded) + chk1 = nod(OLT, bound, hb); + } else if(n->op == OSLICEARR) { + hb = bound; + } else { + hb = nod(OLEN, src, N); + typecheck(&hb, Erv); + walkexpr(&hb, init); + hb = cheapexpr(conv(hb, bt), init); + } + + if(lb != N) { + lb = cheapexpr(conv(lb, bt), init); + if(!bounded) + chk2 = nod(OLT, hb, lb); + } + + if(chk1 != N || chk2 != N) { + chk = nod(OIF, N, N); + chk->nbody = list1(mkcall("panicslice", T, init)); + if(chk1 != N) + chk->ntest = chk1; + if(chk2 != N) { + if(chk->ntest == N) + chk->ntest = chk2; + else + chk->ntest = nod(OOROR, chk->ntest, chk2); + } + typecheck(&chk, Etop); + walkstmt(&chk); + *init = concat(*init, chk->ninit); + chk->ninit = nil; + *init = list(*init, chk); + } + + // prepare new cap, len and offs for backend cgen_slice + // cap = bound [ - lo ] + n->right = N; + n->list = nil; + if(lb == N) + bound = conv(bound, types[TUINT32]); + else + bound = nod(OSUB, conv(bound, types[TUINT32]), conv(lb, types[TUINT32])); + typecheck(&bound, Erv); + walkexpr(&bound, init); + n->list = list(n->list, bound); + + // len = hi [ - lo] + if(lb == N) + hb = conv(hb, types[TUINT32]); + else + hb = nod(OSUB, conv(hb, types[TUINT32]), conv(lb, types[TUINT32])); + typecheck(&hb, Erv); + walkexpr(&hb, init); + n->list = list(n->list, hb); + + // offs = [width *] lo, but omit if zero + if(lb != N) { + if(n->op == OSLICESTR) + w = 1; + else + w = n->type->type->width; + lb = conv(lb, types[TUINTPTR]); + if(w > 1) + lb = nod(OMUL, nodintconst(w), lb); + typecheck(&lb, Erv); + walkexpr(&lb, init); + n->list = list(n->list, lb); + } + +// print("after sliceany: %+N\n", n); + + return n; +} + static Node* eqfor(Type *t) { diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c index e5726c93b9..3c7c8be0e9 100644 --- a/src/pkg/runtime/slice.c +++ b/src/pkg/runtime/slice.c @@ -147,149 +147,6 @@ growslice1(SliceType *t, Slice x, int32 newcap, Slice *ret) runtime·memmove(ret->array, x.array, ret->len * t->elem->size); } -// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any); -void -runtime·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret) -{ - if(hb > old.cap || lb > hb) { - if(debug) { - runtime·prints("runtime.sliceslice: old="); - runtime·printslice(old); - runtime·prints("; lb="); - runtime·printint(lb); - runtime·prints("; hb="); - runtime·printint(hb); - runtime·prints("; width="); - runtime·printint(width); - runtime·prints("\n"); - - runtime·prints("oldarray: nel="); - runtime·printint(old.len); - runtime·prints("; cap="); - runtime·printint(old.cap); - runtime·prints("\n"); - } - runtime·panicslice(); - } - - // new array is inside old array - ret.len = hb - lb; - ret.cap = old.cap - lb; - ret.array = old.array + lb*width; - - FLUSH(&ret); - - if(debug) { - runtime·prints("runtime.sliceslice: old="); - runtime·printslice(old); - runtime·prints("; lb="); - runtime·printint(lb); - runtime·prints("; hb="); - runtime·printint(hb); - runtime·prints("; width="); - runtime·printint(width); - runtime·prints("; ret="); - runtime·printslice(ret); - runtime·prints("\n"); - } -} - -// sliceslice1(old []any, lb uint64, width uint64) (ary []any); -void -runtime·sliceslice1(Slice old, uint64 lb, uint64 width, Slice ret) -{ - if(lb > old.len) { - if(debug) { - runtime·prints("runtime.sliceslice: old="); - runtime·printslice(old); - runtime·prints("; lb="); - runtime·printint(lb); - runtime·prints("; width="); - runtime·printint(width); - runtime·prints("\n"); - - runtime·prints("oldarray: nel="); - runtime·printint(old.len); - runtime·prints("; cap="); - runtime·printint(old.cap); - runtime·prints("\n"); - } - runtime·panicslice(); - } - - // new array is inside old array - ret.len = old.len - lb; - ret.cap = old.cap - lb; - ret.array = old.array + lb*width; - - FLUSH(&ret); - - if(debug) { - runtime·prints("runtime.sliceslice: old="); - runtime·printslice(old); - runtime·prints("; lb="); - runtime·printint(lb); - runtime·prints("; width="); - runtime·printint(width); - runtime·prints("; ret="); - runtime·printslice(ret); - runtime·prints("\n"); - } -} - -// slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any); -void -runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, Slice ret) -{ - if(nel > 0 && old == nil) { - // crash if old == nil. - // could give a better message - // but this is consistent with all the in-line checks - // that the compiler inserts for other uses. - *old = 0; - } - - if(hb > nel || lb > hb) { - if(debug) { - runtime·prints("runtime.slicearray: old="); - runtime·printpointer(old); - runtime·prints("; nel="); - runtime·printint(nel); - runtime·prints("; lb="); - runtime·printint(lb); - runtime·prints("; hb="); - runtime·printint(hb); - runtime·prints("; width="); - runtime·printint(width); - runtime·prints("\n"); - } - runtime·panicslice(); - } - - // new array is inside old array - ret.len = hb-lb; - ret.cap = nel-lb; - ret.array = old + lb*width; - - FLUSH(&ret); - - if(debug) { - runtime·prints("runtime.slicearray: old="); - runtime·printpointer(old); - runtime·prints("; nel="); - runtime·printint(nel); - runtime·prints("; lb="); - runtime·printint(lb); - runtime·prints("; hb="); - runtime·printint(hb); - runtime·prints("; width="); - runtime·printint(width); - runtime·prints("; ret="); - runtime·printslice(ret); - runtime·prints("\n"); - } -} - // copy(to any, fr any, wid uint32) int void runtime·copy(Slice to, Slice fm, uintptr width, int32 ret) diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc index 7e1f8a1e8b..090c4cd20e 100644 --- a/src/pkg/runtime/string.goc +++ b/src/pkg/runtime/string.goc @@ -235,31 +235,6 @@ runtime·strstr(byte *s1, byte *s2) return nil; } -func slicestring(si String, lindex int32, hindex int32) (so String) { - int32 l; - - if(lindex < 0 || lindex > si.len || - hindex < lindex || hindex > si.len) { - runtime·panicslice(); - } - - l = hindex-lindex; - so.str = si.str + lindex; - so.len = l; -} - -func slicestring1(si String, lindex int32) (so String) { - int32 l; - - if(lindex < 0 || lindex > si.len) { - runtime·panicslice(); - } - - l = si.len-lindex; - so.str = si.str + lindex; - so.len = l; -} - func intstring(v int64) (s String) { s = gostringsize(8); s.len = runtime·runetochar(s.str, v); -- 2.48.1