Commit 24699fb0 authored by Keith Randall's avatar Keith Randall

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
parent c0f22945
......@@ -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"
......
......@@ -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
......
......@@ -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);
......
......@@ -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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment