From 69cd91a5981c49eaaa59b33196bdb5586c18d289 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 27 Jan 2015 23:57:12 +0300 Subject: [PATCH] cmd/gc: don't copy []byte during string comparison Currently we allocate a new string during []byte->string conversion in string comparison expressions. String allocation is unnecessary in this case, because comparison does memorize the strings for later use. This change uses slicebytetostringtmp to construct temp string directly from []byte buffer and passes it to runtime.eqstring. Change-Id: If00f1faaee2076baa6f6724d245d5b5e0f59b563 Reviewed-on: https://go-review.googlesource.com/3410 Reviewed-by: Russ Cox --- src/cmd/gc/order.c | 12 ++++++++++++ src/runtime/string.go | 1 + src/runtime/string_test.go | 17 +++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c index 2cd155d4d7..6603efe8d1 100644 --- a/src/cmd/gc/order.c +++ b/src/cmd/gc/order.c @@ -1031,6 +1031,18 @@ orderexpr(Node **np, Order *order) } break; + case OCMPSTR: + orderexpr(&n->left, order); + orderexpr(&n->right, order); + // Mark string(byteSlice) arguments to reuse byteSlice backing + // buffer during conversion. String comparison does not + // memorize the strings for later use, so it is safe. + if(n->left->op == OARRAYBYTESTR) + n->left->op = OARRAYBYTESTRTMP; + if(n->right->op == OARRAYBYTESTR) + n->right->op = OARRAYBYTESTRTMP; + break; + case OINDEXMAP: // key must be addressable orderexpr(&n->left, order); diff --git a/src/runtime/string.go b/src/runtime/string.go index 8aa0dd076d..6f7de4de1e 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -76,6 +76,7 @@ func slicebytetostringtmp(b []byte) string { // First such case is a m[string(k)] lookup where // m is a string-keyed map and k is a []byte. // Second such case is "<"+string(b)+">" concatenation where b is []byte. + // Third such case is string(b)=="foo" comparison where b is []byte. if raceenabled && len(b) > 0 { racereadrangepc(unsafe.Pointer(&b[0]), diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go index 1551ecc82b..03c8948467 100644 --- a/src/runtime/string_test.go +++ b/src/runtime/string_test.go @@ -158,3 +158,20 @@ func TestGostringnocopy(t *testing.T) { t.Errorf("want %d, got %d", max+9, newmax) } } + +func TestCompareTempString(t *testing.T) { + s := "foo" + b := []byte(s) + n := testing.AllocsPerRun(1000, func() { + if string(b) != s { + t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) + } + if string(b) == s { + } else { + t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) + } + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +} -- 2.50.0