1
0
mirror of https://github.com/golang/go synced 2024-11-23 16:30:06 -07:00

runtime: get rid of concatstring's vararg C argument.

Pass as a slice of strings instead.  For 2-5 strings, implement
dedicated routines so no slices are needed.

static call counts in the go binary:
 2 strings: 342 occurrences
 3 strings:  98
 4 strings:  30
 5 strings:  13
6+ strings:  14

Why?  C varags, bad for stack scanning and copying.

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/36380043
This commit is contained in:
Keith Randall 2013-12-03 10:39:19 -08:00
parent c0f2294577
commit 24699fb05c
4 changed files with 60 additions and 26 deletions

View File

@ -23,7 +23,11 @@ char *runtimeimport =
"func @\"\".printnl ()\n"
"func @\"\".printsp ()\n"
"func @\"\".goprintf ()\n"
"func @\"\".concatstring ()\n"
"func @\"\".concatstring2 (? string, ? string) (? string)\n"
"func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
"func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"
"func @\"\".concatstring5 (? string, ? string, ? string, ? string, ? string) (? string)\n"
"func @\"\".concatstrings (? []string) (? string)\n"
"func @\"\".cmpstring (? string, ? string) (? int)\n"
"func @\"\".eqstring (? string, ? string) (? bool)\n"
"func @\"\".intstring (? int64) (? string)\n"

View File

@ -36,8 +36,11 @@ func printnl()
func printsp()
func goprintf()
// filled in by compiler: int n, string, string, ...
func concatstring()
func concatstring2(string, string) string
func concatstring3(string, string, string) string
func concatstring4(string, string, string, string) string
func concatstring5(string, string, string, string, string) string
func concatstrings([]string) string
func cmpstring(string, string) int
func eqstring(string, string) bool

View File

@ -2558,33 +2558,39 @@ mapfndel(char *name, Type *t)
static Node*
addstr(Node *n, NodeList **init)
{
Node *r, *cat, *typstr;
NodeList *in, *args;
int i, count;
Node *r, *cat, *slice;
NodeList *args;
int count;
Type *t;
count = 0;
for(r=n; r->op == OADDSTR; r=r->left)
count++; // r->right
count++; // r
if(count < 2)
yyerror("addstr count %d too small", count);
// prepare call of runtime.catstring of type int, string, string, string
// with as many strings as we have.
cat = syslook("concatstring", 1);
cat->type = T;
cat->ntype = nod(OTFUNC, N, N);
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
typstr = typenod(types[TSTRING]);
for(i=0; i<count; i++)
in = list(in, nod(ODCLFIELD, N, typstr));
cat->ntype->list = in;
cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
// build list of string arguments
args = nil;
for(r=n; r->op == OADDSTR; r=r->left)
args = concat(list1(conv(r->right, types[TSTRING])), args);
args = concat(list1(conv(r, types[TSTRING])), args);
args = concat(list1(nodintconst(count)), args);
if(count <= 5) {
// small numbers of strings use direct runtime helpers.
snprint(namebuf, sizeof(namebuf), "concatstring%d", count);
} else {
// large numbers of strings are passed to the runtime as a slice.
strcpy(namebuf, "concatstrings");
t = typ(TARRAY);
t->type = types[TSTRING];
t->bound = -1;
slice = nod(OCOMPLIT, N, typenod(t));
slice->list = args;
slice->esc = EscNone;
args = list1(slice);
}
cat = syslook(namebuf, 1);
r = nod(OCALL, cat, N);
r->list = args;
typecheck(&r, Erv);

View File

@ -179,14 +179,35 @@ concatstring(intgo n, String *s)
return out;
}
// NOTE: Cannot use func syntax, because we need the ...,
// to signal to the garbage collector that this function does
// not have a fixed size argument count.
#pragma textflag NOSPLIT
void
runtime·concatstring(intgo n, String s1, ...)
{
(&s1)[n] = concatstring(n, &s1);
func concatstring2(s1 String, s2 String) (res String) {
USED(&s2);
res = concatstring(2, &s1);
}
#pragma textflag NOSPLIT
func concatstring3(s1 String, s2 String, s3 String) (res String) {
USED(&s2);
USED(&s3);
res = concatstring(3, &s1);
}
#pragma textflag NOSPLIT
func concatstring4(s1 String, s2 String, s3 String, s4 String) (res String) {
USED(&s2);
USED(&s3);
USED(&s4);
res = concatstring(4, &s1);
}
#pragma textflag NOSPLIT
func concatstring5(s1 String, s2 String, s3 String, s4 String, s5 String) (res String) {
USED(&s2);
USED(&s3);
USED(&s4);
USED(&s5);
res = concatstring(5, &s1);
}
#pragma textflag NOSPLIT
func concatstrings(s Slice) (res String) {
res = concatstring(s.len, (String*)s.array);
}
func eqstring(s1 String, s2 String) (v bool) {