cmd/gc: use 100x less memory for []byte("string")
[]byte("string") was simplifying to
[]byte{0: 0x73, 1: 0x74, 2: 0x72, 3: 0x69, 4: 0x6e, 5: 0x67},
but that latter form takes up much more memory in the compiler.
Preserve the string form and recognize it to turn global variables
initialized this way into linker-initialized data.
Reduces the compiler memory footprint for a large []byte initialized
this way from approximately 10 kB/B to under 100 B/B.
See also issue 6643.
R=golang-codereviews, r, iant, oleku.konko, dave, gobot, bradfitz
CC=golang-codereviews
https://golang.org/cl/15930045
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 2e03898..a00f5c8 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -1263,6 +1263,7 @@
int dsname(Sym *s, int off, char *dat, int ndat);
void dumpobj(void);
Sym* stringsym(char*, int);
+void slicebytes(Node*, char*, int);
LSym* linksym(Sym*);
/*
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index c17be5c..c6ba367 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -253,3 +253,31 @@
return sym;
}
+
+void
+slicebytes(Node *nam, char *s, int len)
+{
+ int off, n, m;
+ static int gen;
+ Sym *sym;
+
+ snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen);
+ sym = pkglookup(namebuf, localpkg);
+ sym->def = newname(sym);
+
+ off = 0;
+ for(n=0; n<len; n+=m) {
+ m = 8;
+ if(m > len-n)
+ m = len-n;
+ off = dsname(sym, off, s+n, m);
+ }
+ ggloblsym(sym, off, 0, 0);
+
+ if(nam->op != ONAME)
+ fatal("slicebytes %N", nam);
+ off = nam->xoffset;
+ off = dsymptr(nam->sym, off, sym, 0);
+ off = duintxx(nam->sym, off, len, widthint);
+ duintxx(nam->sym, off, len, widthint);
+}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 446b111..59c5097 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -378,6 +378,7 @@
InitPlan *p;
InitEntry *e;
int i;
+ Strlit *sval;
switch(r->op) {
default:
@@ -426,6 +427,14 @@
}
break;
+ case OSTRARRAYBYTE:
+ if(l->class == PEXTERN && r->left->op == OLITERAL) {
+ sval = r->left->val.u.sval;
+ slicebytes(l, sval->s, sval->len);
+ return 1;
+ }
+ break;
+
case OARRAYLIT:
initplan(r);
if(isslice(r->type)) {
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 6f8b6ad..4d0a636 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -1406,6 +1406,9 @@
}
break;
case OSTRARRAYBYTE:
+ // do not use stringtoarraylit.
+ // generated code and compiler memory footprint is better without it.
+ break;
case OSTRARRAYRUNE:
if(n->left->op == OLITERAL)
stringtoarraylit(&n);