"func @\"\".intstring (? *[4]byte, ? int64) (? string)\n"
"func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n"
"func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
- "func @\"\".slicerunetostring (? []rune) (? string)\n"
- "func @\"\".stringtoslicebyte (? string) (? []byte)\n"
+ "func @\"\".slicerunetostring (? *[32]byte, ? []rune) (? string)\n"
+ "func @\"\".stringtoslicebyte (? *[32]byte, ? string) (? []byte)\n"
"func @\"\".stringtoslicebytetmp (? string) (? []byte)\n"
- "func @\"\".stringtoslicerune (? string) (? []rune)\n"
+ "func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n"
"func @\"\".stringiter (? string, ? int) (? int)\n"
"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n"
"func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n"
case OMAKEMAP:
case OMAKESLICE:
case ONEW:
- n->escloopdepth = e->loopdepth;
- n->esc = EscNone; // until proven otherwise
- e->noesc = list(e->noesc, n);
- break;
-
+ case OARRAYRUNESTR:
case OARRAYBYTESTR:
+ case OSTRARRAYRUNE:
+ case OSTRARRAYBYTE:
case ORUNESTR:
n->escloopdepth = e->loopdepth;
n->esc = EscNone; // until proven otherwise
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
+ case OARRAYRUNESTR:
case OARRAYBYTESTR:
+ case OSTRARRAYRUNE:
+ case OSTRARRAYBYTE:
case OADDSTR:
case ONEW:
case OCLOSURE:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
+ case OARRAYRUNESTR:
case OARRAYBYTESTR:
+ case OSTRARRAYRUNE:
+ case OSTRARRAYBYTE:
case OADDSTR:
case OMAPLIT:
case ONEW:
func intstring(*[4]byte, int64) string
func slicebytetostring(*[32]byte, []byte) string
func slicebytetostringtmp([]byte) string
-func slicerunetostring([]rune) string
-func stringtoslicebyte(string) []byte
+func slicerunetostring(*[32]byte, []rune) string
+func stringtoslicebyte(*[32]byte, string) []byte
func stringtoslicebytetmp(string) []byte
-func stringtoslicerune(string) []rune
+func stringtoslicerune(*[32]rune, string) []rune
func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv rune)
func slicecopy(to any, fr any, wid uintptr) int
goto ret;
case OARRAYRUNESTR:
- // slicerunetostring([]rune) string;
- n = mkcall("slicerunetostring", n->type, init, n->left);
+ // slicerunetostring(*[32]byte, []rune) string;
+ a = nodnil();
+ if(n->esc == EscNone) {
+ // Create temporary buffer for string on stack.
+ t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
+ a = nod(OADDR, temp(t), N);
+ }
+ n = mkcall("slicerunetostring", n->type, init, a, n->left);
goto ret;
case OSTRARRAYBYTE:
- // stringtoslicebyte(string) []byte;
- n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
+ // stringtoslicebyte(*32[byte], string) []byte;
+ a = nodnil();
+ if(n->esc == EscNone) {
+ // Create temporary buffer for slice on stack.
+ t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]);
+ a = nod(OADDR, temp(t), N);
+ }
+ n = mkcall("stringtoslicebyte", n->type, init, a, conv(n->left, types[TSTRING]));
goto ret;
case OSTRARRAYBYTETMP:
goto ret;
case OSTRARRAYRUNE:
- // stringtoslicerune(string) []rune
- n = mkcall("stringtoslicerune", n->type, init, n->left);
+ // stringtoslicerune(*[32]rune, string) []rune
+ a = nodnil();
+ if(n->esc == EscNone) {
+ // Create temporary buffer for slice on stack.
+ t = aindex(nodintconst(tmpstringbufsize), types[TINT32]);
+ a = nod(OADDR, temp(t), N);
+ }
+ n = mkcall("stringtoslicerune", n->type, init, a, n->left);
goto ret;
case OCMPIFACE:
return *(*string)(unsafe.Pointer(&b))
}
-func stringtoslicebyte(s string) []byte {
- b := rawbyteslice(len(s))
+func stringtoslicebyte(buf *tmpBuf, s string) []byte {
+ var b []byte
+ if buf != nil && len(s) <= len(buf) {
+ b = buf[:len(s)]
+ } else {
+ b = rawbyteslice(len(s))
+ }
copy(b, s)
return b
}
return *(*[]byte)(unsafe.Pointer(&ret))
}
-func stringtoslicerune(s string) []rune {
+func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
// two passes.
// unlike slicerunetostring, no race because strings are immutable.
n := 0
s = s[k:]
n++
}
- a := rawruneslice(n)
+ var a []rune
+ if buf != nil && n <= len(buf) {
+ a = buf[:n]
+ } else {
+ a = rawruneslice(n)
+ }
n = 0
for len(t) > 0 {
r, k := charntorune(t)
return a
}
-func slicerunetostring(a []rune) string {
+func slicerunetostring(buf *tmpBuf, a []rune) string {
if raceenabled && len(a) > 0 {
racereadrangepc(unsafe.Pointer(&a[0]),
uintptr(len(a))*unsafe.Sizeof(a[0]),
for _, r := range a {
size1 += runetochar(dum[:], r)
}
- s, b := rawstring(size1 + 3)
+ s, b := rawstringtmp(buf, size1+3)
size2 := 0
for _, r := range a {
// check for race
return x
}
-func gostringsize(n int) string {
- s, _ := rawstring(n)
- return s
-}
-
func gostring(p *byte) string {
l := findnull(p)
if l == 0 {
func foo21a() func() int {
x := 42 // ERROR "moved to heap: x"
return func() int { // ERROR "func literal escapes to heap"
- x++ // ERROR "&x escapes to heap"
+ x++ // ERROR "&x escapes to heap"
return x
}
}
func ptrlitNoEscape2() {
// Literal does not escape, but element does.
- i := 0 // ERROR "moved to heap: i"
+ i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
sink = *x
}
func ptrlitEscape() {
// Both literal and element escape.
- i := 0 // ERROR "moved to heap: i"
+ i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
sink = x
}
// to just x, and thus &i looks escaping.
func fieldFlowTracking() {
var x StructWithString
- i := 0 // ERROR "moved to heap: i"
+ i := 0 // ERROR "moved to heap: i"
x.p = &i // ERROR "&i escapes to heap"
sink = x.s
}
s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
sink = &s // ERROR "&s escapes to heap"
}
+
+func stringtoslicebyte0() {
+ s := "foo"
+ x := []byte(s) // ERROR "\(\[\]byte\)\(s\) does not escape"
+ _ = x
+}
+
+func stringtoslicebyte1() []byte {
+ s := "foo"
+ return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+}
+
+func stringtoslicebyte2() {
+ s := "foo"
+ sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+}
+
+func stringtoslicerune0() {
+ s := "foo"
+ x := []rune(s) // ERROR "\(\[\]rune\)\(s\) does not escape"
+ _ = x
+}
+
+func stringtoslicerune1() []rune {
+ s := "foo"
+ return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+}
+
+func stringtoslicerune2() {
+ s := "foo"
+ sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+}
+
+func slicerunetostring0() {
+ r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+ s := string(r) // ERROR "string\(r\) does not escape"
+ _ = s
+}
+
+func slicerunetostring1() string {
+ r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+ return string(r) // ERROR "string\(r\) escapes to heap"
+}
+
+func slicerunetostring2() {
+ r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+ sink = string(r) // ERROR "string\(r\) escapes to heap"
+}
func foo21a() func() int {
x := 42 // ERROR "moved to heap: x"
return func() int { // ERROR "func literal escapes to heap"
- x++ // ERROR "&x escapes to heap"
+ x++ // ERROR "&x escapes to heap"
return x
}
}
func ptrlitNoEscape2() {
// Literal does not escape, but element does.
- i := 0 // ERROR "moved to heap: i"
+ i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
sink = *x
}
func ptrlitEscape() {
// Both literal and element escape.
- i := 0 // ERROR "moved to heap: i"
+ i := 0 // ERROR "moved to heap: i"
x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
sink = x
}
// to just x, and thus &i looks escaping.
func fieldFlowTracking() {
var x StructWithString
- i := 0 // ERROR "moved to heap: i"
+ i := 0 // ERROR "moved to heap: i"
x.p = &i // ERROR "&i escapes to heap"
sink = x.s
}
s := string(x) // ERROR "string\(x\) escapes to heap" "moved to heap: s"
sink = &s // ERROR "&s escapes to heap"
}
+
+func stringtoslicebyte0() {
+ s := "foo"
+ x := []byte(s) // ERROR "\(\[\]byte\)\(s\) does not escape"
+ _ = x
+}
+
+func stringtoslicebyte1() []byte {
+ s := "foo"
+ return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+}
+
+func stringtoslicebyte2() {
+ s := "foo"
+ sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap"
+}
+
+func stringtoslicerune0() {
+ s := "foo"
+ x := []rune(s) // ERROR "\(\[\]rune\)\(s\) does not escape"
+ _ = x
+}
+
+func stringtoslicerune1() []rune {
+ s := "foo"
+ return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+}
+
+func stringtoslicerune2() {
+ s := "foo"
+ sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap"
+}
+
+func slicerunetostring0() {
+ r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+ s := string(r) // ERROR "string\(r\) does not escape"
+ _ = s
+}
+
+func slicerunetostring1() string {
+ r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+ return string(r) // ERROR "string\(r\) escapes to heap"
+}
+
+func slicerunetostring2() {
+ r := []rune{1, 2, 3} // ERROR "\[\]rune literal does not escape"
+ sink = string(r) // ERROR "string\(r\) escapes to heap"
+}