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 = ...@@ -23,7 +23,11 @@ char *runtimeimport =
"func @\"\".printnl ()\n" "func @\"\".printnl ()\n"
"func @\"\".printsp ()\n" "func @\"\".printsp ()\n"
"func @\"\".goprintf ()\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 @\"\".cmpstring (? string, ? string) (? int)\n"
"func @\"\".eqstring (? string, ? string) (? bool)\n" "func @\"\".eqstring (? string, ? string) (? bool)\n"
"func @\"\".intstring (? int64) (? string)\n" "func @\"\".intstring (? int64) (? string)\n"
......
...@@ -36,8 +36,11 @@ func printnl() ...@@ -36,8 +36,11 @@ func printnl()
func printsp() func printsp()
func goprintf() func goprintf()
// filled in by compiler: int n, string, string, ... func concatstring2(string, string) string
func concatstring() 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 cmpstring(string, string) int
func eqstring(string, string) bool func eqstring(string, string) bool
......
...@@ -2558,33 +2558,39 @@ mapfndel(char *name, Type *t) ...@@ -2558,33 +2558,39 @@ mapfndel(char *name, Type *t)
static Node* static Node*
addstr(Node *n, NodeList **init) addstr(Node *n, NodeList **init)
{ {
Node *r, *cat, *typstr; Node *r, *cat, *slice;
NodeList *in, *args; NodeList *args;
int i, count; int count;
Type *t;
count = 0; count = 0;
for(r=n; r->op == OADDSTR; r=r->left) for(r=n; r->op == OADDSTR; r=r->left)
count++; // r->right count++; // r->right
count++; // r count++; // r
if(count < 2)
yyerror("addstr count %d too small", count);
// prepare call of runtime.catstring of type int, string, string, string // build list of string arguments
// 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));
args = nil; args = nil;
for(r=n; r->op == OADDSTR; r=r->left) for(r=n; r->op == OADDSTR; r=r->left)
args = concat(list1(conv(r->right, types[TSTRING])), args); args = concat(list1(conv(r->right, types[TSTRING])), args);
args = concat(list1(conv(r, 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 = nod(OCALL, cat, N);
r->list = args; r->list = args;
typecheck(&r, Erv); typecheck(&r, Erv);
......
...@@ -179,14 +179,35 @@ concatstring(intgo n, String *s) ...@@ -179,14 +179,35 @@ concatstring(intgo n, String *s)
return out; 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 #pragma textflag NOSPLIT
void func concatstring2(s1 String, s2 String) (res String) {
runtime·concatstring(intgo n, String s1, ...) USED(&s2);
{ res = concatstring(2, &s1);
(&s1)[n] = concatstring(n, &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) { 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