1
0
mirror of https://github.com/golang/go synced 2024-10-04 06:21:23 -06: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 @\"\".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"

View File

@ -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

View File

@ -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);

View File

@ -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) {