gc: make string x + y + z + ... + w efficient
1 malloc per concatenation.
R=ken2
CC=golang-dev
https://golang.org/cl/2124045
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index ce86e12..12f870d 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -20,7 +20,7 @@
"func \"\".printnl ()\n"
"func \"\".printsp ()\n"
"func \"\".printf ()\n"
- "func \"\".catstring (? string, ? string) string\n"
+ "func \"\".concatstring ()\n"
"func \"\".cmpstring (? string, ? string) int\n"
"func \"\".slicestring (? string, ? int, ? int) string\n"
"func \"\".slicestring1 (? string, ? int) string\n"
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 2531344..36ed7e9 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -33,7 +33,9 @@
func printsp()
func printf()
-func catstring(string, string) string
+// filled in by compiler: int n, string, string, ...
+func concatstring()
+
func cmpstring(string, string) int
func slicestring(string, int, int) string
func slicestring1(string, int) string
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index fc8f19e..8039774 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -17,6 +17,7 @@
static NodeList* paramstoheap(Type **argin, int out);
static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*);
+static Node* addstr(Node*, NodeList**);
static NodeList* walkdefstack;
@@ -1205,10 +1206,7 @@
goto ret;
case OADDSTR:
- // sys_catstring(s1, s2)
- n = mkcall("catstring", n->type, init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TSTRING]));
+ n = addstr(n, init);
goto ret;
case OSLICESTR:
@@ -2234,3 +2232,42 @@
argtype(fn, t->type);
return fn;
}
+
+static Node*
+addstr(Node *n, NodeList **init)
+{
+ Node *r, *cat, *typstr;
+ NodeList *in, *args;
+ int i, count;
+
+ count = 0;
+ for(r=n; r->op == OADDSTR; r=r->left)
+ count++; // r->right
+ count++; // r
+
+ // 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));
+
+ 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);
+
+ r = nod(OCALL, cat, N);
+ r->list = args;
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ r->type = n->type;
+
+ return r;
+}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index ca76729..88f53e2 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -395,6 +395,7 @@
void* mal(uintptr);
uint32 cmpstring(String, String);
String catstring(String, String);
+String concatstring(int32, String*);
String gostring(byte*);
String gostringn(byte*, int32);
String gostringnocopy(byte*);
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index ec45735..7bf8f8b 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -114,9 +114,33 @@
return s3;
}
+String
+concatstring(int32 n, String *s)
+{
+ int32 i, l;
+ String out;
-func catstring(s1 String, s2 String) (s3 String) {
- s3 = catstring(s1, s2);
+ l = 0;
+ for(i=0; i<n; i++) {
+ if(l + s[i].len < l)
+ throw("string concatenation too long");
+ l += s[i].len;
+ }
+
+ out = gostringsize(l);
+ l = 0;
+ for(i=0; i<n; i++) {
+ mcpy(out.str+l, s[i].str, s[i].len);
+ l += s[i].len;
+ }
+ return out;
+}
+
+#pragma textflag 7
+// s1 is the first of n strings.
+// the output string follows.
+func concatstring(n int32, s1 String) {
+ (&s1)[n] = concatstring(n, &s1);
}
uint32