"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" +
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)
}
}
- 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
} 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
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)
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)
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
_, 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)
+ }
+}
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"