1
0
mirror of https://github.com/golang/go synced 2024-11-18 11:14:39 -07:00

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 #38265 and #38266.
Wow, does that take a long time to run.

Updates #36890

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% 

Change-Id: Idb29fa6a81d6a82bfd3b65740b98cf3275ca0a78
Reviewed-on: https://go-review.googlesource.com/c/go/+/227163
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Josh Bleecher Snyder 2020-01-31 21:01:55 -08:00
parent ade0811dc8
commit b6feb03b24
10 changed files with 153 additions and 109 deletions

View File

@ -57,9 +57,9 @@ var runtimeDecls = [...]struct {
{"concatstrings", funcTag, 35}, {"concatstrings", funcTag, 35},
{"cmpstring", funcTag, 36}, {"cmpstring", funcTag, 36},
{"intstring", funcTag, 39}, {"intstring", funcTag, 39},
{"slicebytetostring", funcTag, 41}, {"slicebytetostring", funcTag, 40},
{"slicebytetostringtmp", funcTag, 42}, {"slicebytetostringtmp", funcTag, 41},
{"slicerunetostring", funcTag, 45}, {"slicerunetostring", funcTag, 44},
{"stringtoslicebyte", funcTag, 46}, {"stringtoslicebyte", funcTag, 46},
{"stringtoslicerune", funcTag, 49}, {"stringtoslicerune", funcTag, 49},
{"slicecopy", funcTag, 51}, {"slicecopy", funcTag, 51},
@ -241,20 +241,20 @@ func runtimeTypes() []*types.Type {
typs[37] = types.NewArray(typs[0], 4) typs[37] = types.NewArray(typs[0], 4)
typs[38] = types.NewPtr(typs[37]) typs[38] = types.NewPtr(typs[37])
typs[39] = functype(nil, []*Node{anonfield(typs[38]), anonfield(typs[19])}, []*Node{anonfield(typs[25])}) typs[39] = functype(nil, []*Node{anonfield(typs[38]), anonfield(typs[19])}, []*Node{anonfield(typs[25])})
typs[40] = types.NewSlice(typs[0]) typs[40] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
typs[41] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[40])}, []*Node{anonfield(typs[25])}) typs[41] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
typs[42] = functype(nil, []*Node{anonfield(typs[40])}, []*Node{anonfield(typs[25])}) typs[42] = types.Runetype
typs[43] = types.Runetype typs[43] = types.NewSlice(typs[42])
typs[44] = types.NewSlice(typs[43]) typs[44] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[43])}, []*Node{anonfield(typs[25])})
typs[45] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[44])}, []*Node{anonfield(typs[25])}) typs[45] = types.NewSlice(typs[0])
typs[46] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25])}, []*Node{anonfield(typs[40])}) typs[46] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25])}, []*Node{anonfield(typs[45])})
typs[47] = types.NewArray(typs[43], 32) typs[47] = types.NewArray(typs[42], 32)
typs[48] = types.NewPtr(typs[47]) typs[48] = types.NewPtr(typs[47])
typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[25])}, []*Node{anonfield(typs[44])}) typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[25])}, []*Node{anonfield(typs[43])})
typs[50] = types.Types[TUINTPTR] typs[50] = types.Types[TUINTPTR]
typs[51] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2]), anonfield(typs[50])}, []*Node{anonfield(typs[11])}) typs[51] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[50])}, []*Node{anonfield(typs[11])})
typs[52] = functype(nil, []*Node{anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[11])}) typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[53] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[11])}, []*Node{anonfield(typs[43]), anonfield(typs[11])}) typs[53] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[11])}, []*Node{anonfield(typs[42]), anonfield(typs[11])})
typs[54] = functype(nil, []*Node{anonfield(typs[25])}, []*Node{anonfield(typs[11])}) typs[54] = functype(nil, []*Node{anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])}) typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
typs[56] = types.Types[TUNSAFEPTR] typs[56] = types.Types[TUNSAFEPTR]
@ -293,7 +293,7 @@ func runtimeTypes() []*types.Type {
typs[89] = tostruct([]*Node{namedfield("enabled", typs[15]), namedfield("pad", typs[88]), namedfield("needed", typs[15]), namedfield("cgo", typs[15]), namedfield("alignme", typs[21])}) typs[89] = tostruct([]*Node{namedfield("enabled", typs[15]), namedfield("pad", typs[88]), namedfield("needed", typs[15]), namedfield("cgo", typs[15]), namedfield("alignme", typs[21])})
typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil) typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[11])}) typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11])}, []*Node{anonfield(typs[11])})
typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[15])}) typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[15])}) typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
typs[95] = types.NewPtr(typs[15]) typs[95] = types.NewPtr(typs[15])

View File

@ -69,13 +69,13 @@ func concatstrings(*[32]byte, []string) string
func cmpstring(string, string) int func cmpstring(string, string) int
func intstring(*[4]byte, int64) string func intstring(*[4]byte, int64) string
func slicebytetostring(*[32]byte, []byte) string func slicebytetostring(buf *[32]byte, ptr *byte, n int) string
func slicebytetostringtmp([]byte) string func slicebytetostringtmp(ptr *byte, n int) string
func slicerunetostring(*[32]byte, []rune) string func slicerunetostring(*[32]byte, []rune) string
func stringtoslicebyte(*[32]byte, string) []byte func stringtoslicebyte(*[32]byte, string) []byte
func stringtoslicerune(*[32]rune, string) []rune func stringtoslicerune(*[32]rune, string) []rune
func slicecopy(to any, fr any, wid uintptr) int func slicecopy(toPtr *any, toLen int, frPtr *any, frLen int, wid uintptr) int
func slicestringcopy(to any, fr any) int func slicestringcopy(toPtr *byte, toLen int, fr string) int
func decoderune(string, int) (retv rune, retk int) func decoderune(string, int) (retv rune, retk int)
func countrunes(string) int func countrunes(string) int
@ -162,7 +162,7 @@ var writeBarrier struct {
// *byte is really *runtime.Type // *byte is really *runtime.Type
func typedmemmove(typ *byte, dst *any, src *any) func typedmemmove(typ *byte, dst *any, src *any)
func typedmemclr(typ *byte, dst *any) func typedmemclr(typ *byte, dst *any)
func typedslicecopy(typ *byte, dst any, src any) int func typedslicecopy(typ *byte, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
func selectnbsend(hchan chan<- any, elem *any) bool func selectnbsend(hchan chan<- any, elem *any) bool
func selectnbrecv(elem *any, hchan <-chan any) bool func selectnbrecv(elem *any, hchan <-chan any) bool

View File

@ -3277,10 +3277,7 @@ func init() {
// Compiler frontend optimizations emit OBYTES2STRTMP nodes // Compiler frontend optimizations emit OBYTES2STRTMP nodes
// for the backend instead of slicebytetostringtmp calls // for the backend instead of slicebytetostringtmp calls
// when not instrumenting. // when not instrumenting.
slice := args[0] return s.newValue2(ssa.OpStringMake, n.Type, args[0], args[1])
ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice)
len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice)
return s.newValue2(ssa.OpStringMake, n.Type, ptr, len)
}, },
all...) all...)
} }

View File

@ -923,6 +923,21 @@ func (o Op) IsSlice3() bool {
return false return false
} }
// slicePtrLen extracts the pointer and length from a slice.
// This constructs two nodes referring to n, so n must be a cheapexpr.
func (n *Node) slicePtrLen() (ptr, len *Node) {
var init Nodes
c := cheapexpr(n, &init)
if c != n || init.Len() != 0 {
Fatalf("slicePtrLen not cheap: %v", n)
}
ptr = nod(OSPTR, n, nil)
ptr.Type = n.Type.Elem().PtrTo()
len = nod(OLEN, n, nil)
len.Type = types.Types[TINT]
return ptr, len
}
// labeledControl returns the control flow Node (for, switch, select) // labeledControl returns the control flow Node (for, switch, select)
// associated with the label n, if any. // associated with the label n, if any.
func (n *Node) labeledControl() *Node { func (n *Node) labeledControl() *Node {

View File

@ -1414,13 +1414,15 @@ opswitch:
t := types.NewArray(types.Types[TUINT8], tmpstringbufsize) t := types.NewArray(types.Types[TUINT8], tmpstringbufsize)
a = nod(OADDR, temp(t), nil) a = nod(OADDR, temp(t), nil)
} }
fn := "slicebytetostring"
if n.Op == ORUNES2STR { if n.Op == ORUNES2STR {
fn = "slicerunetostring" // slicerunetostring(*[32]byte, []rune) string
n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
} else {
// slicebytetostring(*[32]byte, ptr *byte, n int) string
n.Left = cheapexpr(n.Left, init)
ptr, len := n.Left.slicePtrLen()
n = mkcall("slicebytetostring", n.Type, init, a, ptr, len)
} }
// slicebytetostring(*[32]byte, []byte) string
// slicerunetostring(*[32]byte, []rune) string
n = mkcall(fn, n.Type, init, a, n.Left)
case OBYTES2STRTMP: case OBYTES2STRTMP:
n.Left = walkexpr(n.Left, init) n.Left = walkexpr(n.Left, init)
@ -1429,8 +1431,10 @@ opswitch:
// to avoid a function call to slicebytetostringtmp. // to avoid a function call to slicebytetostringtmp.
break break
} }
// slicebytetostringtmp([]byte) string // slicebytetostringtmp(ptr *byte, n int) string
n = mkcall("slicebytetostringtmp", n.Type, init, n.Left) n.Left = cheapexpr(n.Left, init)
ptr, len := n.Left.slicePtrLen()
n = mkcall("slicebytetostringtmp", n.Type, init, ptr, len)
case OSTR2BYTES: case OSTR2BYTES:
s := n.Left s := n.Left
@ -2645,6 +2649,8 @@ func appendslice(n *Node, init *Nodes) *Node {
l1 := n.List.First() l1 := n.List.First()
l2 := n.List.Second() l2 := n.List.Second()
l2 = cheapexpr(l2, init)
n.List.SetSecond(l2)
var nodes Nodes var nodes Nodes
@ -2682,35 +2688,45 @@ func appendslice(n *Node, init *Nodes) *Node {
if elemtype.HasHeapPointer() { if elemtype.HasHeapPointer() {
// copy(s[len(l1):], l2) // copy(s[len(l1):], l2)
nptr1 := nod(OSLICE, s, nil) nptr1 := nod(OSLICE, s, nil)
nptr1.Type = s.Type
nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil) nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
nptr1 = cheapexpr(nptr1, &nodes)
nptr2 := l2 nptr2 := l2
Curfn.Func.setWBPos(n.Pos) Curfn.Func.setWBPos(n.Pos)
// instantiate typedslicecopy(typ *type, dst any, src any) int // instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
fn := syslook("typedslicecopy") fn := syslook("typedslicecopy")
fn = substArgTypes(fn, l1.Type, l2.Type) fn = substArgTypes(fn, l1.Type.Elem(), l2.Type.Elem())
ncopy = mkcall1(fn, types.Types[TINT], &nodes, typename(elemtype), nptr1, nptr2) ptr1, len1 := nptr1.slicePtrLen()
ptr2, len2 := nptr2.slicePtrLen()
ncopy = mkcall1(fn, types.Types[TINT], &nodes, typename(elemtype), ptr1, len1, ptr2, len2)
} else if instrumenting && !compiling_runtime { } else if instrumenting && !compiling_runtime {
// rely on runtime to instrument copy. // rely on runtime to instrument copy.
// copy(s[len(l1):], l2) // copy(s[len(l1):], l2)
nptr1 := nod(OSLICE, s, nil) nptr1 := nod(OSLICE, s, nil)
nptr1.Type = s.Type
nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil) nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
nptr1 = cheapexpr(nptr1, &nodes)
nptr2 := l2 nptr2 := l2
if l2.Type.IsString() { if l2.Type.IsString() {
// instantiate func slicestringcopy(to any, fr any) int // instantiate func slicestringcopy(toPtr *byte, toLen int, fr string) int
fn := syslook("slicestringcopy") fn := syslook("slicestringcopy")
fn = substArgTypes(fn, l1.Type, l2.Type) ptr, len := nptr1.slicePtrLen()
ncopy = mkcall1(fn, types.Types[TINT], &nodes, nptr1, nptr2) str := nod(OCONVNOP, nptr2, nil)
str.Type = types.Types[TSTRING]
ncopy = mkcall1(fn, types.Types[TINT], &nodes, ptr, len, str)
} else { } else {
// instantiate func slicecopy(to any, fr any, wid uintptr) int // instantiate func slicecopy(to any, fr any, wid uintptr) int
fn := syslook("slicecopy") fn := syslook("slicecopy")
fn = substArgTypes(fn, l1.Type, l2.Type) fn = substArgTypes(fn, l1.Type.Elem(), l2.Type.Elem())
ncopy = mkcall1(fn, types.Types[TINT], &nodes, nptr1, nptr2, nodintconst(elemtype.Width)) ptr1, len1 := nptr1.slicePtrLen()
ptr2, len2 := nptr2.slicePtrLen()
ncopy = mkcall1(fn, types.Types[TINT], &nodes, ptr1, len1, ptr2, len2, nodintconst(elemtype.Width))
} }
} else { } else {
@ -3009,20 +3025,31 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
func copyany(n *Node, init *Nodes, runtimecall bool) *Node { func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
if n.Left.Type.Elem().HasHeapPointer() { if n.Left.Type.Elem().HasHeapPointer() {
Curfn.Func.setWBPos(n.Pos) Curfn.Func.setWBPos(n.Pos)
fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type) fn := writebarrierfn("typedslicecopy", n.Left.Type.Elem(), n.Right.Type.Elem())
return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right) n.Left = cheapexpr(n.Left, init)
ptrL, lenL := n.Left.slicePtrLen()
n.Right = cheapexpr(n.Right, init)
ptrR, lenR := n.Right.slicePtrLen()
return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), ptrL, lenL, ptrR, lenR)
} }
if runtimecall { if runtimecall {
if n.Right.Type.IsString() { if n.Right.Type.IsString() {
fn := syslook("slicestringcopy") fn := syslook("slicestringcopy")
fn = substArgTypes(fn, n.Left.Type, n.Right.Type) n.Left = cheapexpr(n.Left, init)
return mkcall1(fn, n.Type, init, n.Left, n.Right) ptr, len := n.Left.slicePtrLen()
str := nod(OCONVNOP, n.Right, nil)
str.Type = types.Types[TSTRING]
return mkcall1(fn, n.Type, init, ptr, len, str)
} }
fn := syslook("slicecopy") fn := syslook("slicecopy")
fn = substArgTypes(fn, n.Left.Type, n.Right.Type) fn = substArgTypes(fn, n.Left.Type.Elem(), n.Right.Type.Elem())
return mkcall1(fn, n.Type, init, n.Left, n.Right, nodintconst(n.Left.Type.Elem().Width)) n.Left = cheapexpr(n.Left, init)
ptrL, lenL := n.Left.slicePtrLen()
n.Right = cheapexpr(n.Right, init)
ptrR, lenR := n.Right.slicePtrLen()
return mkcall1(fn, n.Type, init, ptrL, lenL, ptrR, lenR, nodintconst(n.Left.Type.Elem().Width))
} }
n.Left = walkexpr(n.Left, init) n.Left = walkexpr(n.Left, init)

View File

@ -76,23 +76,24 @@ func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
cgoCheckTypedBlock(typ, src, off, size) cgoCheckTypedBlock(typ, src, off, size)
} }
// cgoCheckSliceCopy is called when copying n elements of a slice from // cgoCheckSliceCopy is called when copying n elements of a slice.
// src to dst. typ is the element type of the 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 // It throws if the program is copying slice elements that contain Go pointers
// into non-Go memory. // into non-Go memory.
//go:nosplit //go:nosplit
//go:nowritebarrier //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 { if typ.ptrdata == 0 {
return return
} }
if !cgoIsGoPointer(src.array) { if !cgoIsGoPointer(src) {
return return
} }
if cgoIsGoPointer(dst.array) { if cgoIsGoPointer(dst) {
return return
} }
p := src.array p := src
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
cgoCheckTypedBlock(typ, p, 0, typ.size) cgoCheckTypedBlock(typ, p, 0, typ.size)
p = add(p, typ.size) p = add(p, typ.size)

View File

@ -231,16 +231,14 @@ func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr) {
} }
//go:nosplit //go:nosplit
func typedslicecopy(typ *_type, dst, src slice) int { func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe.Pointer, srcLen int) int {
n := dst.len n := dstLen
if n > src.len { if n > srcLen {
n = src.len n = srcLen
} }
if n == 0 { if n == 0 {
return 0 return 0
} }
dstp := dst.array
srcp := src.array
// The compiler emits calls to typedslicecopy before // The compiler emits calls to typedslicecopy before
// instrumentation runs, so unlike the other copying and // instrumentation runs, so unlike the other copying and
@ -249,19 +247,19 @@ func typedslicecopy(typ *_type, dst, src slice) int {
if raceenabled { if raceenabled {
callerpc := getcallerpc() callerpc := getcallerpc()
pc := funcPC(slicecopy) pc := funcPC(slicecopy)
racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc) racewriterangepc(dstPtr, uintptr(n)*typ.size, callerpc, pc)
racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc) racereadrangepc(srcPtr, uintptr(n)*typ.size, callerpc, pc)
} }
if msanenabled { if msanenabled {
msanwrite(dstp, uintptr(n)*typ.size) msanwrite(dstPtr, uintptr(n)*typ.size)
msanread(srcp, uintptr(n)*typ.size) msanread(srcPtr, uintptr(n)*typ.size)
} }
if writeBarrier.cgo { if writeBarrier.cgo {
cgoCheckSliceCopy(typ, dst, src, n) cgoCheckSliceCopy(typ, dstPtr, srcPtr, n)
} }
if dstp == srcp { if dstPtr == srcPtr {
return n return n
} }
@ -272,11 +270,11 @@ func typedslicecopy(typ *_type, dst, src slice) int {
size := uintptr(n) * typ.size size := uintptr(n) * typ.size
if writeBarrier.needed { if writeBarrier.needed {
pwsize := size - typ.size + typ.ptrdata pwsize := size - typ.size + typ.ptrdata
bulkBarrierPreWrite(uintptr(dstp), uintptr(srcp), pwsize) bulkBarrierPreWrite(uintptr(dstPtr), uintptr(srcPtr), pwsize)
} }
// See typedmemmove for a discussion of the race between the // See typedmemmove for a discussion of the race between the
// barrier and memmove. // barrier and memmove.
memmove(dstp, srcp, size) memmove(dstPtr, srcPtr, size)
return n return n
} }
@ -306,7 +304,7 @@ func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
memmove(dst.array, src.array, size) memmove(dst.array, src.array, size)
return n 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 // typedmemclr clears the typed memory at ptr with type typ. The

View File

@ -277,13 +277,14 @@ func getHugePageSize() uintptr {
if fd < 0 { if fd < 0 {
return 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) closefd(fd)
if n <= 0 { if n <= 0 {
return 0 return 0
} }
l := n - 1 // remove trailing newline n-- // remove trailing newline
v, ok := atoi(slicebytetostringtmp(numbuf[:l])) v, ok := atoi(slicebytetostringtmp((*byte)(ptr), int(n)))
if !ok || v < 0 { if !ok || v < 0 {
v = 0 v = 0
} }

View File

@ -194,14 +194,14 @@ func isPowerOfTwo(x uintptr) bool {
return x&(x-1) == 0 return x&(x-1) == 0
} }
func slicecopy(to, fm slice, width uintptr) int { func slicecopy(toPtr unsafe.Pointer, toLen int, fmPtr unsafe.Pointer, fmLen int, width uintptr) int {
if fm.len == 0 || to.len == 0 { if fmLen == 0 || toLen == 0 {
return 0 return 0
} }
n := fm.len n := fmLen
if to.len < n { if toLen < n {
n = to.len n = toLen
} }
if width == 0 { if width == 0 {
@ -211,43 +211,43 @@ func slicecopy(to, fm slice, width uintptr) int {
if raceenabled { if raceenabled {
callerpc := getcallerpc() callerpc := getcallerpc()
pc := funcPC(slicecopy) pc := funcPC(slicecopy)
racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc) racereadrangepc(fmPtr, uintptr(n*int(width)), callerpc, pc)
racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc) racewriterangepc(toPtr, uintptr(n*int(width)), callerpc, pc)
} }
if msanenabled { if msanenabled {
msanread(fm.array, uintptr(n*int(width))) msanread(fmPtr, uintptr(n*int(width)))
msanwrite(to.array, uintptr(n*int(width))) msanwrite(toPtr, uintptr(n*int(width)))
} }
size := uintptr(n) * width size := uintptr(n) * width
if size == 1 { // common case worth about 2x to do here if size == 1 { // common case worth about 2x to do here
// TODO: is this still worth it with new memmove impl? // 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 { } else {
memmove(to.array, fm.array, size) memmove(toPtr, fmPtr, size)
} }
return n return n
} }
func slicestringcopy(to []byte, fm string) int { func slicestringcopy(toPtr *byte, toLen int, fm string) int {
if len(fm) == 0 || len(to) == 0 { if len(fm) == 0 || toLen == 0 {
return 0 return 0
} }
n := len(fm) n := len(fm)
if len(to) < n { if toLen < n {
n = len(to) n = toLen
} }
if raceenabled { if raceenabled {
callerpc := getcallerpc() callerpc := getcallerpc()
pc := funcPC(slicestringcopy) pc := funcPC(slicestringcopy)
racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc) racewriterangepc(unsafe.Pointer(toPtr), uintptr(n), callerpc, pc)
} }
if msanenabled { 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 return n
} }

View File

@ -71,27 +71,30 @@ func concatstring5(buf *tmpBuf, a [5]string) string {
return concatstrings(buf, a[:]) return concatstrings(buf, a[:])
} }
// 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, // Buf is a fixed-size buffer for the result,
// it is not nil if the result does not escape. // it is not nil if the result does not escape.
func slicebytetostring(buf *tmpBuf, b []byte) (str string) { func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
l := len(b) if n == 0 {
if l == 0 {
// Turns out to be a relatively common case. // Turns out to be a relatively common case.
// Consider that you want to parse out data between parens in "foo()bar", // Consider that you want to parse out data between parens in "foo()bar",
// you find the indices and convert the subslice to string. // you find the indices and convert the subslice to string.
return "" return ""
} }
if raceenabled { if raceenabled {
racereadrangepc(unsafe.Pointer(&b[0]), racereadrangepc(unsafe.Pointer(ptr),
uintptr(l), uintptr(n),
getcallerpc(), getcallerpc(),
funcPC(slicebytetostring)) funcPC(slicebytetostring))
} }
if msanenabled { if msanenabled {
msanread(unsafe.Pointer(&b[0]), uintptr(l)) msanread(unsafe.Pointer(ptr), uintptr(n))
} }
if l == 1 { if n == 1 {
p := unsafe.Pointer(&staticuint64s[b[0]]) p := unsafe.Pointer(&staticuint64s[*ptr])
if sys.BigEndian { if sys.BigEndian {
p = add(p, 7) p = add(p, 7)
} }
@ -101,14 +104,14 @@ func slicebytetostring(buf *tmpBuf, b []byte) (str string) {
} }
var p unsafe.Pointer var p unsafe.Pointer
if buf != nil && len(b) <= len(buf) { if buf != nil && n <= len(buf) {
p = unsafe.Pointer(buf) p = unsafe.Pointer(buf)
} else { } else {
p = mallocgc(uintptr(len(b)), nil, false) p = mallocgc(uintptr(n), nil, false)
} }
stringStructOf(&str).str = p stringStructOf(&str).str = p
stringStructOf(&str).len = len(b) stringStructOf(&str).len = n
memmove(p, (*(*slice)(unsafe.Pointer(&b))).array, uintptr(len(b))) memmove(p, unsafe.Pointer(ptr), uintptr(n))
return return
} }
@ -123,7 +126,7 @@ func stringDataOnStack(s string) bool {
func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) { func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
if buf != nil && l <= len(buf) { if buf != nil && l <= len(buf) {
b = buf[:l] b = buf[:l]
s = slicebytetostringtmp(b) s = slicebytetostringtmp(&b[0], len(b))
} else { } else {
s, b = rawstring(l) s, b = rawstring(l)
} }
@ -144,17 +147,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. // 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)+">" concatenation where b is []byte.
// - Used for string(b)=="foo" comparison where b is []byte. // - Used for string(b)=="foo" comparison where b is []byte.
func slicebytetostringtmp(b []byte) string { func slicebytetostringtmp(ptr *byte, n int) (str string) {
if raceenabled && len(b) > 0 { if raceenabled && n > 0 {
racereadrangepc(unsafe.Pointer(&b[0]), racereadrangepc(unsafe.Pointer(ptr),
uintptr(len(b)), uintptr(n),
getcallerpc(), getcallerpc(),
funcPC(slicebytetostringtmp)) funcPC(slicebytetostringtmp))
} }
if msanenabled && len(b) > 0 { if msanenabled && n > 0 {
msanread(unsafe.Pointer(&b[0]), uintptr(len(b))) 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 { func stringtoslicebyte(buf *tmpBuf, s string) []byte {
@ -239,7 +244,7 @@ func intstring(buf *[4]byte, v int64) (s string) {
var b []byte var b []byte
if buf != nil { if buf != nil {
b = buf[:] b = buf[:]
s = slicebytetostringtmp(b) s = slicebytetostringtmp(&b[0], len(b))
} else { } else {
s, b = rawstring(4) s, b = rawstring(4)
} }