]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: allocate stack buffer for ORUNESTR
authorDmitry Vyukov <dvyukov@google.com>
Wed, 28 Jan 2015 05:42:20 +0000 (08:42 +0300)
committerDmitry Vyukov <dvyukov@google.com>
Wed, 28 Jan 2015 20:37:20 +0000 (20:37 +0000)
If result of string(i) does not escape,
allocate a [4]byte temp on stack for it.

Change-Id: If31ce9447982929d5b3b963fd0830efae4247c37
Reviewed-on: https://go-review.googlesource.com/3411
Reviewed-by: Russ Cox <rsc@golang.org>
src/cmd/gc/builtin.c
src/cmd/gc/esc.c
src/cmd/gc/runtime.go
src/cmd/gc/walk.c
src/runtime/string.go
src/runtime/string_test.go
test/escape2.go
test/escape2n.go

index 6682bfb66d762cc9f71ec18b6e9c275281a3f037..fcd5685cdce0d60aac394082bce123ae360da21e 100644 (file)
@@ -33,7 +33,7 @@ char *runtimeimport =
        "func @\"\".concatstrings (? *[32]byte, ? []string) (? string)\n"
        "func @\"\".cmpstring (? string, ? string) (? int)\n"
        "func @\"\".eqstring (? string, ? string) (? bool)\n"
-       "func @\"\".intstring (? int64) (? string)\n"
+       "func @\"\".intstring (? *[4]byte, ? int64) (? string)\n"
        "func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n"
        "func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
        "func @\"\".slicerunetostring (? []rune) (? string)\n"
index b636059749a2c3a31d9cfcdd445d45dae6ad52ab..c4bf961c97687bc4d595270e0afa4fc74bfb852e 100644 (file)
@@ -695,6 +695,7 @@ esc(EscState *e, Node *n, Node *up)
                break;
 
        case OARRAYBYTESTR:
+       case ORUNESTR:
                n->escloopdepth = e->loopdepth;
                n->esc = EscNone;  // until proven otherwise
                e->noesc = list(e->noesc, n);
@@ -824,6 +825,7 @@ escassign(EscState *e, Node *dst, Node *src)
        case ONEW:
        case OCLOSURE:
        case OCALLPART:
+       case ORUNESTR:
                escflows(e, dst, src);
                break;
 
@@ -1249,6 +1251,7 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
        case ONEW:
        case OCLOSURE:
        case OCALLPART:
+       case ORUNESTR:
                if(leaks) {
                        src->esc = EscHeap;
                        if(debug['m'])
index 13b19ca5e24666ee785cb11e2c5546586093c41a..1b16ebb9c635073b8ac6e4208fd69f40303b7431 100644 (file)
@@ -47,7 +47,7 @@ func concatstrings(*[32]byte, []string) string
 
 func cmpstring(string, string) int
 func eqstring(string, string) bool
-func intstring(int64) string
+func intstring(*[4]byte, int64) string
 func slicebytetostring(*[32]byte, []byte) string
 func slicebytetostringtmp([]byte) string
 func slicerunetostring([]rune) string
index 513aadf4ba5ab0a5fd9695698639f14273edad78..5625d6b5dd374dfcf728272672a60e24314da62d 100644 (file)
@@ -1370,9 +1370,14 @@ walkexpr(Node **np, NodeList **init)
                goto ret;
 
        case ORUNESTR:
-               // sys_intstring(v)
-               n = mkcall("intstring", n->type, init,
-                       conv(n->left, types[TINT64]));
+               a = nodnil();
+               if(n->esc == EscNone) {
+                       t = aindex(nodintconst(4), types[TUINT8]);
+                       var = temp(t);
+                       a = nod(OADDR, var, N);
+               }
+               // intstring(*[4]byte, rune)
+               n = mkcall("intstring", n->type, init, a, conv(n->left, types[TINT64]));
                goto ret;
 
        case OARRAYBYTESTR:
index 9ec6f320ebdafe3ef665ddbe64f55dbe7d8f780f..58198d0e1b988dfca31f10ad4f8466115e0465a9 100644 (file)
@@ -185,8 +185,15 @@ type stringStruct struct {
        len int
 }
 
-func intstring(v int64) string {
-       s, b := rawstring(4)
+func intstring(buf *[4]byte, v int64) string {
+       var s string
+       var b []byte
+       if buf != nil {
+               b = buf[:]
+               s = slicebytetostringtmp(b)
+       } else {
+               s, b = rawstring(4)
+       }
        n := runetochar(b, rune(v))
        return s[:n]
 }
index 249f431e18278de88b82c84673b7ed01fd554e16..27a44ad645fa7f3a7d44e1488c1cccbafb4c2ee6 100644 (file)
@@ -186,3 +186,38 @@ func TestStringOnStack(t *testing.T) {
                t.Fatalf("want: '%v', got '%v'", want, s)
        }
 }
+
+func TestIntString(t *testing.T) {
+       // Non-escaping result of intstring.
+       s := ""
+       for i := 0; i < 4; i++ {
+               s += string(i+'0') + string(i+'0'+1)
+       }
+       if want := "01122334"; s != want {
+               t.Fatalf("want '%v', got '%v'", want, s)
+       }
+
+       // Escaping result of intstring.
+       var a [4]string
+       for i := 0; i < 4; i++ {
+               a[i] = string(i + '0')
+       }
+       s = a[0] + a[1] + a[2] + a[3]
+       if want := "0123"; s != want {
+               t.Fatalf("want '%v', got '%v'", want, s)
+       }
+}
+
+func TestIntStringAllocs(t *testing.T) {
+       unknown := '0'
+       n := testing.AllocsPerRun(1000, func() {
+               s1 := string(unknown)
+               s2 := string(unknown + 1)
+               if s1 == s2 {
+                       t.Fatalf("bad")
+               }
+       })
+       if n != 0 {
+               t.Fatalf("want 0 allocs, got %v", n)
+       }
+}
index 57352a152ca50a6a505c3ea91b8ccbf29c49f2d7..1523d9f1ff221e337ad7ac7b8cbaaf7fe412a2d2 100644 (file)
@@ -1630,3 +1630,24 @@ func addstr3() {
        s2 := s[0:1]
        sink = s2
 }
+
+func intstring0() bool {
+       // string does not escape
+       x := '0'
+       s := string(x) // ERROR "string\(x\) does not escape"
+       return s == "0"
+}
+
+func intstring1() string {
+       // string does not escape, but the buffer does
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap"
+       return s
+}
+
+func intstring2() {
+       // string escapes to heap
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
+       sink = &s      // ERROR "&s escapes to heap"
+}
index 6769906e3069e60982195b10c4aa84b25a566efd..03c0f4b75dfa8c7195eb24a74d4368612442c380 100644 (file)
@@ -1630,3 +1630,24 @@ func addstr3() {
        s2 := s[0:1]
        sink = s2
 }
+
+func intstring0() bool {
+       // string does not escape
+       x := '0'
+       s := string(x) // ERROR "string\(x\) does not escape"
+       return s == "0"
+}
+
+func intstring1() string {
+       // string does not escape, but the buffer does
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap"
+       return s
+}
+
+func intstring2() {
+       // string escapes to heap
+       x := '0'
+       s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
+       sink = &s      // ERROR "&s escapes to heap"
+}