order.out = append(order.out, n)
cleantemp(t, order)
- // n->right is the expression being ranged over.
- // order it, and then make a copy if we need one.
- // We almost always do, to ensure that we don't
- // see any value changes made during the loop.
- // Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny).
- // The exception is ranging over an array value (not a slice, not a pointer to array),
- // which must make a copy to avoid seeing updates made during
- // the range body. Ranging over an array value is uncommon though.
case ORANGE:
- t := marktemp(order)
+ // n.Right is the expression being ranged over.
+ // order it, and then make a copy if we need one.
+ // We almost always do, to ensure that we don't
+ // see any value changes made during the loop.
+ // Usually the copy is cheap (e.g., array pointer,
+ // chan, slice, string are all tiny).
+ // The exception is ranging over an array value
+ // (not a slice, not a pointer to array),
+ // which must make a copy to avoid seeing updates made during
+ // the range body. Ranging over an array value is uncommon though.
+
+ // Mark []byte(str) range expression to reuse string backing storage.
+ // It is safe because the storage cannot be mutated.
+ if n.Right.Op == OSTRARRAYBYTE {
+ n.Right.Op = OSTRARRAYBYTETMP
+ }
+ t := marktemp(order)
n.Right = orderexpr(n.Right, order, nil)
switch n.Type.Etype {
default:
Fatalf("orderstmt range %v", n.Type)
- // Mark []byte(str) range expression to reuse string backing storage.
- // It is safe because the storage cannot be mutated.
case TARRAY:
- if n.Right.Op == OSTRARRAYBYTE {
- n.Right.Op = OSTRARRAYBYTETMP
- }
if n.List.Len() < 2 || isblank(n.List.Second()) {
// for i := range x will only use x once, to compute len(x).
// No need to copy it.
}
fallthrough
- // chan, string, slice, array ranges use value multiple times.
- // make copy.
- // fall through
case TCHAN, TSTRING:
+ // chan, string, slice, array ranges use value multiple times.
+ // make copy.
r := n.Right
if r.Type.Etype == TSTRING && r.Type != Types[TSTRING] {
n.Right = ordercopyexpr(r, r.Type, order, 0)
- // copy the map value in case it is a map literal.
- // TODO(rsc): Make tmp = literal expressions reuse tmp.
- // For maps tmp is just one word so it hardly matters.
case TMAP:
+ // copy the map value in case it is a map literal.
+ // TODO(rsc): Make tmp = literal expressions reuse tmp.
+ // For maps tmp is just one word so it hardly matters.
r := n.Right
-
n.Right = ordercopyexpr(r, r.Type, order, 0)
// n->alloc is the temp for the iterator.
"testing"
)
+// Strings and slices that don't escape and fit into tmpBuf are stack allocated,
+// which defeats using AllocsPerRun to test other optimizations.
+const sizeNoStack = 100
+
func BenchmarkCompareStringEqual(b *testing.B) {
bytes := []byte("Hello Gophers!")
s1, s2 := string(bytes), string(bytes)
}
func TestCompareTempString(t *testing.T) {
- s := "foo"
+ s := strings.Repeat("x", sizeNoStack)
b := []byte(s)
n := testing.AllocsPerRun(1000, func() {
if string(b) != s {
}
func TestRangeStringCast(t *testing.T) {
- s := "abc"
+ s := strings.Repeat("x", sizeNoStack)
n := testing.AllocsPerRun(1000, func() {
for i, c := range []byte(s) {
if c != s[i] {