]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/gc: allocate backing storage for non-escaping interfaces on stack
authorDavid Chase <drchase@google.com>
Fri, 27 Mar 2015 15:21:14 +0000 (11:21 -0400)
committerDavid Chase <drchase@google.com>
Mon, 30 Mar 2015 16:11:22 +0000 (16:11 +0000)
Extend escape analysis to convT2E and conT2I. If the interface value
does not escape supply runtime with a stack buffer for the object copy.

This is a straight port from .c to .go of Dmitry's patch

Change-Id: Ic315dd50d144d94dd3324227099c116be5ca70b6
Reviewed-on: https://go-review.googlesource.com/8201
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
src/cmd/internal/gc/builtin.go
src/cmd/internal/gc/builtin/runtime.go
src/cmd/internal/gc/esc.go
src/cmd/internal/gc/walk.go
src/runtime/iface.go
src/runtime/iface_test.go
test/escape2.go

index d39bc2b02f71d336cb93c9b97c5ffcd80cc7c414..13ee7d72891b6e227b1224603b29d9d3075c567a 100644 (file)
@@ -50,8 +50,8 @@ const runtimeimport = "" +
        "func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" +
        "func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" +
        "func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" +
-       "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n" +
-       "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n" +
+       "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any, @\"\".buf·4 *any) (@\"\".ret·1 any)\n" +
+       "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any, @\"\".buf·6 *any) (@\"\".ret·1 any)\n" +
        "func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
        "func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
        "func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
index 554d787feb173e8fbce03c8744086102e2ae4ed4..0cf1fb2894dc2d737947941ea21d9450dff3b860 100644 (file)
@@ -63,8 +63,8 @@ func slicestringcopy(to any, fr any) int
 func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte)
 func convI2E(elem any) (ret any)
 func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem *any) (ret any)
-func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any)
+func convT2E(typ *byte, elem, buf *any) (ret any)
+func convT2I(typ *byte, typ2 *byte, cache **byte, elem, buf *any) (ret any)
 
 // interface type assertions  x.(T)
 func assertE2E(typ *byte, iface any, ret *any)
index 6d9b72019c5074d4e0e9d56817fd5eb7a95a7f81..10c6b5ed88594551c6036117a17b5ca16d8e5470 100644 (file)
@@ -653,12 +653,11 @@ func esc(e *EscState, n *Node, up *Node) {
                        }
                }
 
-       case OCONV, OCONVNOP:
+       case OCONV,
+               OCONVNOP:
                escassign(e, n, n.Left)
 
        case OCONVIFACE:
-               // We don't allocate storage for OCONVIFACE on stack yet,
-               // but mark it as EscNone merely to get debug output for tests.
                n.Esc = EscNone // until proven otherwise
                e.noesc = list(e.noesc, n)
                n.Escloopdepth = e.loopdepth
index c6ad507e27c6d58554306d0439a09c78d31364fa..75d08d40c464f89038d8a5c4ea36915f59026af4 100644 (file)
@@ -1040,9 +1040,25 @@ func walkexpr(np **Node, init **NodeList) {
                        } else {
                                ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
                        }
+                       dowidth(n.Left.Type)
+                       r := nodnil()
+                       if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
+                               // Allocate stack buffer for value stored in interface.
+                               r = temp(n.Left.Type)
+                               r = Nod(OAS, r, nil) // zero temp
+                               typecheck(&r, Etop)
+                               *init = list(*init, r)
+                               r = Nod(OADDR, r.Left, nil)
+                               typecheck(&r, Erv)
+                       }
+                       ll = list(ll, r)
                }
 
-               substArgTypes(fn, n.Left.Type, n.Type)
+               if !Isinter(n.Left.Type) {
+                       substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
+               } else {
+                       substArgTypes(fn, n.Left.Type, n.Type)
+               }
                dowidth(fn.Type)
                n = Nod(OCALL, fn, nil)
                n.List = ll
index c60aa47b2f8a12625dc89b3de999c0f34f80fc28..0d4989b2e5372fa2631d3d922072b0fbac90a18a 100644 (file)
@@ -130,13 +130,15 @@ func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
        return tab
 }
 
-func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
+func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e interface{}) {
        ep := (*eface)(unsafe.Pointer(&e))
        if isDirectIface(t) {
                ep._type = t
                typedmemmove(t, unsafe.Pointer(&ep.data), elem)
        } else {
-               x := newobject(t)
+               if x == nil {
+                       x = newobject(t)
+               }
                // TODO: We allocate a zeroed object only to overwrite it with
                // actual data.  Figure out how to avoid zeroing.  Also below in convT2I.
                typedmemmove(t, x, elem)
@@ -146,7 +148,7 @@ func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
        return
 }
 
-func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) (i fInterface) {
+func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i fInterface) {
        tab := (*itab)(atomicloadp(unsafe.Pointer(cache)))
        if tab == nil {
                tab = getitab(inter, t, false)
@@ -157,7 +159,9 @@ func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer)
                pi.tab = tab
                typedmemmove(t, unsafe.Pointer(&pi.data), elem)
        } else {
-               x := newobject(t)
+               if x == nil {
+                       x = newobject(t)
+               }
                typedmemmove(t, x, elem)
                pi.tab = tab
                pi.data = x
index f632a65629a2c4e7549bc08c2034311bf52acdd9..7f27baa61fb9b96eb846ed7c0a9700474d58c084 100644 (file)
@@ -221,3 +221,43 @@ func BenchmarkAssertE2E2Blank(b *testing.B) {
                _, ok = e.(interface{})
        }
 }
+
+func TestNonEscapingConvT2E(t *testing.T) {
+       m := make(map[interface{}]bool)
+       m[42] = true
+       if !m[42] {
+               t.Fatalf("42 is not present in the map")
+       }
+       if m[0] {
+               t.Fatalf("0 is present in the map")
+       }
+
+       n := testing.AllocsPerRun(1000, func() {
+               if m[0] {
+                       t.Fatalf("0 is present in the map")
+               }
+       })
+       if n != 0 {
+               t.Fatalf("want 0 allocs, got %v", n)
+       }
+}
+
+func TestNonEscapingConvT2I(t *testing.T) {
+       m := make(map[I1]bool)
+       m[TM(42)] = true
+       if !m[TM(42)] {
+               t.Fatalf("42 is not present in the map")
+       }
+       if m[TM(0)] {
+               t.Fatalf("0 is present in the map")
+       }
+
+       n := testing.AllocsPerRun(1000, func() {
+               if m[TM(0)] {
+                       t.Fatalf("0 is present in the map")
+               }
+       })
+       if n != 0 {
+               t.Fatalf("want 0 allocs, got %v", n)
+       }
+}
index 591e6e1469b43da0bcfc07f2ad643149978f7b26..65dbd7a2fef46da96cb51090a0dc66733b95deb4 100644 (file)
@@ -1787,7 +1787,7 @@ func makemap1() map[int]int {
 
 func makemap2() {
        m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
-       sink = m        // ERROR "m escapes to heap"
+       sink = m               // ERROR "m escapes to heap"
 }
 
 func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape"