compiler,runtime: pass only ptr and len to some runtime calls
authorIan Lance Taylor <iant@golang.org>
Mon, 27 Jul 2020 22:19:54 +0000 (15:19 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 28 Jul 2020 00:05:17 +0000 (17:05 -0700)
This ports https://golang.org/cl/227163 to the Go frontend.
This is a step toward moving up to the go1.15rc1 release.

Original CL description:

    cmd/compile,runtime: pass only ptr and len to some runtime calls

    Some runtime calls accept a slice, but only use ptr and len.
    This change modifies most such routines to accept only ptr and len.

    After this change, the only runtime calls that accept an unnecessary
    cap arg are concatstrings and slicerunetostring.
    Neither is particularly common, and both are complicated to modify.

    Negligible compiler performance impact. Shrinks binaries a little.
    There are only a few regressions; the one I investigated was
    due to register allocation fluctuation.

    Passes 'go test -race std cmd', modulo golang/go#38265 and golang/go#38266.
    Wow, does that take a long time to run.

    file      before    after     Δ       %
    compile   19655024  19655152  +128    +0.001%
    cover     5244840   5236648   -8192   -0.156%
    dist      3662376   3658280   -4096   -0.112%
    link      6680056   6675960   -4096   -0.061%
    pprof     14789844  14777556  -12288  -0.083%
    test2json 2824744   2820648   -4096   -0.145%
    trace     11647876  11639684  -8192   -0.070%
    vet       8260472   8256376   -4096   -0.050%
    total     115163736 115118808 -44928  -0.039%

For golang/go#36890

Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/245099

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/runtime.def
libgo/go/runtime/cgocheck.go
libgo/go/runtime/mbarrier.go
libgo/go/runtime/os_linux.go
libgo/go/runtime/slice.go
libgo/go/runtime/string.go

index 12e48c1993289de1f3fe22ebadf720a4c7862592..64a655e911efa49965f5431381ab2c8547d72b6a 100644 (file)
@@ -1,4 +1,4 @@
-8b9c7fb00ccaf1d4bcc8d581a1a4d46a35771b77
+63bc2430187efe5ff47e9c7b9cd6d40b350ee7d7
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 327f9403b39d8665342f8d0fa5a348a9e7707bd8..90f860bd7353a19b490795e44375a27c2ebc2687 100644 (file)
@@ -4157,45 +4157,43 @@ Type_conversion_expression::do_get_backend(Translate_context* context)
       go_assert(e->integer_type() != NULL);
       go_assert(this->expr_->is_variable());
 
-      Runtime::Function code;
+      Expression* buf;
+      if (this->no_escape_ && !this->no_copy_)
+        {
+          Type* byte_type = Type::lookup_integer_type("uint8");
+          Expression* buflen =
+            Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
+          Type* array_type = Type::make_array_type(byte_type, buflen);
+          buf = Expression::make_allocation(array_type, loc);
+          buf->allocation_expression()->set_allocate_on_stack();
+          buf->allocation_expression()->set_no_zero();
+        }
+      else
+        buf = Expression::make_nil(loc);
+
       if (e->integer_type()->is_byte())
         {
+         Expression* ptr =
+           Expression::make_slice_info(this->expr_, SLICE_INFO_VALUE_POINTER,
+                                       loc);
+         Expression* len =
+           Expression::make_slice_info(this->expr_, SLICE_INFO_LENGTH, loc);
           if (this->no_copy_)
             {
               if (gogo->debug_optimization())
                 go_debug(loc, "no copy string([]byte)");
-              Expression* ptr = Expression::make_slice_info(this->expr_,
-                                                            SLICE_INFO_VALUE_POINTER,
-                                                            loc);
-              Expression* len = Expression::make_slice_info(this->expr_,
-                                                            SLICE_INFO_LENGTH,
-                                                            loc);
               Expression* str = Expression::make_string_value(ptr, len, loc);
               return str->get_backend(context);
             }
-          code = Runtime::SLICEBYTETOSTRING;
+         return Runtime::make_call(Runtime::SLICEBYTETOSTRING, loc, 3, buf,
+                                   ptr, len)->get_backend(context);
         }
       else
         {
           go_assert(e->integer_type()->is_rune());
-          code = Runtime::SLICERUNETOSTRING;
-        }
-
-      Expression* buf;
-      if (this->no_escape_)
-        {
-          Type* byte_type = Type::lookup_integer_type("uint8");
-          Expression* buflen =
-            Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
-          Type* array_type = Type::make_array_type(byte_type, buflen);
-          buf = Expression::make_allocation(array_type, loc);
-          buf->allocation_expression()->set_allocate_on_stack();
-          buf->allocation_expression()->set_no_zero();
-        }
-      else
-        buf = Expression::make_nil(loc);
-      return Runtime::make_call(code, loc, 2, buf,
-                               this->expr_)->get_backend(context);
+         return Runtime::make_call(Runtime::SLICERUNETOSTRING, loc, 2, buf,
+                                   this->expr_)->get_backend(context);
+       }
     }
   else if (type->is_slice_type() && expr_type->is_string_type())
     {
@@ -8397,8 +8395,16 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
         if (et->has_pointer())
           {
             Expression* td = Expression::make_type_descriptor(et, loc);
+           Expression* pd =
+             Expression::make_slice_info(arg1, SLICE_INFO_VALUE_POINTER, loc);
+           Expression* ld =
+             Expression::make_slice_info(arg1, SLICE_INFO_LENGTH, loc);
+           Expression* ps =
+             Expression::make_slice_info(arg2, SLICE_INFO_VALUE_POINTER, loc);
+           Expression* ls =
+             Expression::make_slice_info(arg2, SLICE_INFO_LENGTH, loc);
             ret = Runtime::make_call(Runtime::TYPEDSLICECOPY, loc,
-                                     3, td, arg1, arg2);
+                                     5, td, pd, ld, ps, ls);
           }
         else
           {
index 2ef0f94133dad75112c42920ab45ea33e5ed79f8..a9500797b4d4b196ebcc2e507bed1427433e50db 100644 (file)
@@ -47,7 +47,7 @@ DEF_GO_RUNTIME(INTSTRING, "runtime.intstring", P2(POINTER, INT64), R1(STRING))
 
 // Convert a []byte to a string.
 DEF_GO_RUNTIME(SLICEBYTETOSTRING, "runtime.slicebytetostring",
-              P2(POINTER, SLICE), R1(STRING))
+              P3(POINTER, POINTER, INT), R1(STRING))
 
 // Convert a []rune to a string.
 DEF_GO_RUNTIME(SLICERUNETOSTRING, "runtime.slicerunetostring",
@@ -249,17 +249,16 @@ DEF_GO_RUNTIME(CLOSE, "runtime.closechan", P1(CHAN), R0())
 
 
 // Copy.
-DEF_GO_RUNTIME(SLICECOPY, "runtime.slicecopy", P3(SLICE, SLICE, UINTPTR),
-              R1(INT))
+DEF_GO_RUNTIME(SLICECOPY, "runtime.slicecopy",
+              P5(POINTER, INT, POINTER, INT, UINTPTR), R1(INT))
 
 // Copy from string.
-DEF_GO_RUNTIME(SLICESTRINGCOPY, "runtime.slicestringcopy", P2(SLICE, STRING),
-              R1(INT))
+DEF_GO_RUNTIME(SLICESTRINGCOPY, "runtime.slicestringcopy",
+              P3(POINTER, INT, STRING), R1(INT))
 
 // Copy of value containing pointers.
 DEF_GO_RUNTIME(TYPEDSLICECOPY, "runtime.typedslicecopy",
-              P3(TYPE, SLICE, SLICE), R1(INT))
-
+              P5(TYPE, POINTER, INT, POINTER, INT), R1(INT))
 
 // Grow a slice for append.
 DEF_GO_RUNTIME(GROWSLICE, "runtime.growslice",
index c03bafe424c0d764f6ca5cf737d73998c99bc6f3..42fdfe80280b1ec1c652410b3724e72285b17b92 100644 (file)
@@ -76,23 +76,24 @@ func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
        cgoCheckTypedBlock(typ, src, off, size)
 }
 
-// cgoCheckSliceCopy is called when copying n elements of a slice from
-// src to dst.  typ is the element type of the slice.
+// cgoCheckSliceCopy is called when copying n elements of a slice.
+// src and dst are pointers to the first element of the slice.
+// typ is the element type of the slice.
 // It throws if the program is copying slice elements that contain Go pointers
 // into non-Go memory.
 //go:nosplit
 //go:nowritebarrier
-func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
+func cgoCheckSliceCopy(typ *_type, dst, src unsafe.Pointer, n int) {
        if typ.ptrdata == 0 {
                return
        }
-       if !cgoIsGoPointer(src.array) {
+       if !cgoIsGoPointer(src) {
                return
        }
-       if cgoIsGoPointer(dst.array) {
+       if cgoIsGoPointer(dst) {
                return
        }
-       p := src.array
+       p := src
        for i := 0; i < n; i++ {
                cgoCheckTypedBlock(typ, p, 0, typ.size)
                p = add(p, typ.size)
index e66b50d1927e32b786b2a08debe6ff634a0580ae..a4f9b3c03506594dc212e97bcab30a87e825c1bc 100644 (file)
@@ -219,16 +219,14 @@ func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size
 }
 
 //go:nosplit
-func typedslicecopy(typ *_type, dst, src slice) int {
-       n := dst.len
-       if n > src.len {
-               n = src.len
+func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe.Pointer, srcLen int) int {
+       n := dstLen
+       if n > srcLen {
+               n = srcLen
        }
        if n == 0 {
                return 0
        }
-       dstp := dst.array
-       srcp := src.array
 
        // The compiler emits calls to typedslicecopy before
        // instrumentation runs, so unlike the other copying and
@@ -237,19 +235,19 @@ func typedslicecopy(typ *_type, dst, src slice) int {
        if raceenabled {
                callerpc := getcallerpc()
                pc := funcPC(slicecopy)
-               racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc)
-               racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
+               racewriterangepc(dstPtr, uintptr(n)*typ.size, callerpc, pc)
+               racereadrangepc(srcPtr, uintptr(n)*typ.size, callerpc, pc)
        }
        if msanenabled {
-               msanwrite(dstp, uintptr(n)*typ.size)
-               msanread(srcp, uintptr(n)*typ.size)
+               msanwrite(dstPtr, uintptr(n)*typ.size)
+               msanread(srcPtr, uintptr(n)*typ.size)
        }
 
        if writeBarrier.cgo {
-               cgoCheckSliceCopy(typ, dst, src, n)
+               cgoCheckSliceCopy(typ, dstPtr, srcPtr, n)
        }
 
-       if dstp == srcp {
+       if dstPtr == srcPtr {
                return n
        }
 
@@ -259,11 +257,11 @@ func typedslicecopy(typ *_type, dst, src slice) int {
        // before calling typedslicecopy.
        size := uintptr(n) * typ.size
        if writeBarrier.needed {
-               bulkBarrierPreWrite(uintptr(dstp), uintptr(srcp), size)
+               bulkBarrierPreWrite(uintptr(dstPtr), uintptr(srcPtr), size)
        }
        // See typedmemmove for a discussion of the race between the
        // barrier and memmove.
-       memmove(dstp, srcp, size)
+       memmove(dstPtr, srcPtr, size)
        return n
 }
 
@@ -293,7 +291,7 @@ func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
                memmove(dst.array, src.array, size)
                return n
        }
-       return typedslicecopy(elemType, dst, src)
+       return typedslicecopy(elemType, dst.array, dst.len, src.array, src.len)
 }
 
 // typedmemclr clears the typed memory at ptr with type typ. The
index 1e86446655743af472f025dc3d19a76b4ec5b934..5d5506467156e65fc93778088ab3f7d7cf3d4c3e 100644 (file)
@@ -207,13 +207,14 @@ func getHugePageSize() uintptr {
        if fd < 0 {
                return 0
        }
-       n := read(fd, noescape(unsafe.Pointer(&numbuf[0])), int32(len(numbuf)))
+       ptr := noescape(unsafe.Pointer(&numbuf[0]))
+       n := read(fd, ptr, int32(len(numbuf)))
        closefd(fd)
        if n <= 0 {
                return 0
        }
-       l := n - 1 // remove trailing newline
-       v, ok := atoi(slicebytetostringtmp(numbuf[:l]))
+       n-- // remove trailing newline
+       v, ok := atoi(slicebytetostringtmp((*byte)(ptr), int(n)))
        if !ok || v < 0 {
                v = 0
        }
index b61c2b10c7e6f406d9ec76e3ff3f137c9377ce05..519735392a9b766f0eead008c1f150d0622f25fa 100644 (file)
@@ -199,14 +199,14 @@ func isPowerOfTwo(x uintptr) bool {
        return x&(x-1) == 0
 }
 
-func slicecopy(to, fm slice, width uintptr) int {
-       if fm.len == 0 || to.len == 0 {
+func slicecopy(toPtr unsafe.Pointer, toLen int, fmPtr unsafe.Pointer, fmLen int, width uintptr) int {
+       if fmLen == 0 || toLen == 0 {
                return 0
        }
 
-       n := fm.len
-       if to.len < n {
-               n = to.len
+       n := fmLen
+       if toLen < n {
+               n = toLen
        }
 
        if width == 0 {
@@ -216,43 +216,43 @@ func slicecopy(to, fm slice, width uintptr) int {
        if raceenabled {
                callerpc := getcallerpc()
                pc := funcPC(slicecopy)
-               racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
-               racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
+               racewriterangepc(toPtr, uintptr(n*int(width)), callerpc, pc)
+               racereadrangepc(fmPtr, uintptr(n*int(width)), callerpc, pc)
        }
        if msanenabled {
-               msanwrite(to.array, uintptr(n*int(width)))
-               msanread(fm.array, uintptr(n*int(width)))
+               msanwrite(toPtr, uintptr(n*int(width)))
+               msanread(fmPtr, uintptr(n*int(width)))
        }
 
        size := uintptr(n) * width
        if size == 1 { // common case worth about 2x to do here
                // TODO: is this still worth it with new memmove impl?
-               *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
+               *(*byte)(toPtr) = *(*byte)(fmPtr) // known to be a byte pointer
        } else {
-               memmove(to.array, fm.array, size)
+               memmove(toPtr, fmPtr, size)
        }
        return n
 }
 
-func slicestringcopy(to []byte, fm string) int {
-       if len(fm) == 0 || len(to) == 0 {
+func slicestringcopy(toPtr *byte, toLen int, fm string) int {
+       if len(fm) == 0 || toLen == 0 {
                return 0
        }
 
        n := len(fm)
-       if len(to) < n {
-               n = len(to)
+       if toLen < n {
+               n = toLen
        }
 
        if raceenabled {
                callerpc := getcallerpc()
                pc := funcPC(slicestringcopy)
-               racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
+               racewriterangepc(unsafe.Pointer(toPtr), uintptr(n), callerpc, pc)
        }
        if msanenabled {
-               msanwrite(unsafe.Pointer(&to[0]), uintptr(n))
+               msanwrite(unsafe.Pointer(toPtr), uintptr(n))
        }
 
-       memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n))
+       memmove(unsafe.Pointer(toPtr), stringStructOf(&fm).str, uintptr(n))
        return n
 }
index df4cae7bcef8bba5b7e183270b02f14a91730ead..7b66a1b447d95f6f783252d1cbe5edbc5255195f 100644 (file)
@@ -70,47 +70,50 @@ func concatstrings(buf *tmpBuf, p *string, n int) string {
        return s
 }
 
+// slicebytetostring converts a byte slice to a string.
+// It is inserted by the compiler into generated code.
+// ptr is a pointer to the first element of the slice;
+// n is the length of the slice.
 // Buf is a fixed-size buffer for the result,
 // it is not nil if the result does not escape.
-func slicebytetostring(buf *tmpBuf, b []byte) (str string) {
-       l := len(b)
-       if l == 0 {
+func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
+       if n == 0 {
                // Turns out to be a relatively common case.
                // Consider that you want to parse out data between parens in "foo()bar",
                // you find the indices and convert the subslice to string.
                return ""
        }
        if raceenabled {
-               racereadrangepc(unsafe.Pointer(&b[0]),
-                       uintptr(l),
+               racereadrangepc(unsafe.Pointer(ptr),
+                       uintptr(n),
                        getcallerpc(),
                        funcPC(slicebytetostring))
        }
        if msanenabled {
-               msanread(unsafe.Pointer(&b[0]), uintptr(l))
+               msanread(unsafe.Pointer(ptr), uintptr(n))
        }
-       if l == 1 {
-               stringStructOf(&str).str = unsafe.Pointer(&staticbytes[b[0]])
+       if n == 1 {
+               stringStructOf(&str).str = unsafe.Pointer(&staticbytes[*ptr])
                stringStructOf(&str).len = 1
                return
        }
 
        var p unsafe.Pointer
-       if buf != nil && len(b) <= len(buf) {
+       if buf != nil && n <= len(buf) {
                p = unsafe.Pointer(buf)
        } else {
-               p = mallocgc(uintptr(len(b)), nil, false)
+               p = mallocgc(uintptr(n), nil, false)
        }
        stringStructOf(&str).str = p
-       stringStructOf(&str).len = len(b)
-       memmove(p, (*(*slice)(unsafe.Pointer(&b))).array, uintptr(len(b)))
+       stringStructOf(&str).len = n
+       memmove(p, unsafe.Pointer(ptr), uintptr(n))
        return
 }
 
 func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
        if buf != nil && l <= len(buf) {
                b = buf[:l]
-               s = slicebytetostringtmp(b)
+               s = slicebytetostringtmp(&b[0], len(b))
        } else {
                s, b = rawstring(l)
        }
@@ -131,17 +134,19 @@ func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
 //   where k is []byte, T1 to Tn is a nesting of struct and array literals.
 // - Used for "<"+string(b)+">" concatenation where b is []byte.
 // - Used for string(b)=="foo" comparison where b is []byte.
-func slicebytetostringtmp(b []byte) string {
-       if raceenabled && len(b) > 0 {
-               racereadrangepc(unsafe.Pointer(&b[0]),
-                       uintptr(len(b)),
+func slicebytetostringtmp(ptr *byte, n int) (str string) {
+       if raceenabled && n > 0 {
+               racereadrangepc(unsafe.Pointer(ptr),
+                       uintptr(n),
                        getcallerpc(),
                        funcPC(slicebytetostringtmp))
        }
-       if msanenabled && len(b) > 0 {
-               msanread(unsafe.Pointer(&b[0]), uintptr(len(b)))
+       if msanenabled && n > 0 {
+               msanread(unsafe.Pointer(ptr), uintptr(n))
        }
-       return *(*string)(unsafe.Pointer(&b))
+       stringStructOf(&str).str = unsafe.Pointer(ptr)
+       stringStructOf(&str).len = n
+       return
 }
 
 func stringtoslicebyte(buf *tmpBuf, s string) []byte {
@@ -232,7 +237,7 @@ func intstring(buf *[4]byte, v int64) (s string) {
        var b []byte
        if buf != nil {
                b = buf[:]
-               s = slicebytetostringtmp(b)
+               s = slicebytetostringtmp(&b[0], len(b))
        } else {
                s, b = rawstring(4)
        }