From e5cfd498576dc7bda771fa7987765bb1dbe9f4f8 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 11 Oct 2021 21:50:32 -0600 Subject: go-patches: make unsafe.Slice fast Signed-off-by: Jason A. Donenfeld --- ...ow-builtin-write-function-to-be-redirecte.patch | 2 +- ...nch.go1.17-cmd-compile-speed-up-unsafe.Sl.patch | 331 +++++++++++++++++++++ 2 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 go-patches/0002-release-branch.go1.17-cmd-compile-speed-up-unsafe.Sl.patch diff --git a/go-patches/0001-runtime-allow-builtin-write-function-to-be-redirecte.patch b/go-patches/0001-runtime-allow-builtin-write-function-to-be-redirecte.patch index c2a5dd52..b72675bd 100644 --- a/go-patches/0001-runtime-allow-builtin-write-function-to-be-redirecte.patch +++ b/go-patches/0001-runtime-allow-builtin-write-function-to-be-redirecte.patch @@ -55,5 +55,5 @@ index 5a4ceaf43d..68c01805a5 100644 return write1(fd, p, n) } -- -2.32.0 +2.33.0 diff --git a/go-patches/0002-release-branch.go1.17-cmd-compile-speed-up-unsafe.Sl.patch b/go-patches/0002-release-branch.go1.17-cmd-compile-speed-up-unsafe.Sl.patch new file mode 100644 index 00000000..42a71f88 --- /dev/null +++ b/go-patches/0002-release-branch.go1.17-cmd-compile-speed-up-unsafe.Sl.patch @@ -0,0 +1,331 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Mon, 11 Oct 2021 21:31:47 -0600 +Subject: [PATCH] [release-branch.go1.17] cmd/compile: speed up unsafe.Slice by + omitting checks + +unsafe.Slice is already an unsafe operation, like unsafe.Pointer casts. +So, assume the user knows what they're doing, unless checkptr is used, +in which case, we can then emit the checker code, just like +unsafe.Pointer casts do. + +Fixes #48798. + +Change-Id: Ice1f615b49fe13556f71495f303d4ff0eb794bd9 +--- + src/cmd/compile/internal/typecheck/builtin.go | 179 +++++++++--------- + .../internal/typecheck/builtin/runtime.go | 2 - + src/cmd/compile/internal/walk/builtin.go | 19 +- + test/unsafebuiltins.go | 30 +-- + 4 files changed, 92 insertions(+), 138 deletions(-) + +diff --git a/src/cmd/compile/internal/typecheck/builtin.go b/src/cmd/compile/internal/typecheck/builtin.go +index 833b17b414..add59020a7 100644 +--- a/src/cmd/compile/internal/typecheck/builtin.go ++++ b/src/cmd/compile/internal/typecheck/builtin.go +@@ -136,72 +136,70 @@ var runtimeDecls = [...]struct { + {"makeslice64", funcTag, 113}, + {"makeslicecopy", funcTag, 114}, + {"growslice", funcTag, 116}, +- {"unsafeslice", funcTag, 117}, +- {"unsafeslice64", funcTag, 118}, +- {"unsafeslicecheckptr", funcTag, 118}, +- {"memmove", funcTag, 119}, +- {"memclrNoHeapPointers", funcTag, 120}, +- {"memclrHasPointers", funcTag, 120}, +- {"memequal", funcTag, 121}, +- {"memequal0", funcTag, 122}, +- {"memequal8", funcTag, 122}, +- {"memequal16", funcTag, 122}, +- {"memequal32", funcTag, 122}, +- {"memequal64", funcTag, 122}, +- {"memequal128", funcTag, 122}, +- {"f32equal", funcTag, 123}, +- {"f64equal", funcTag, 123}, +- {"c64equal", funcTag, 123}, +- {"c128equal", funcTag, 123}, +- {"strequal", funcTag, 123}, +- {"interequal", funcTag, 123}, +- {"nilinterequal", funcTag, 123}, +- {"memhash", funcTag, 124}, +- {"memhash0", funcTag, 125}, +- {"memhash8", funcTag, 125}, +- {"memhash16", funcTag, 125}, +- {"memhash32", funcTag, 125}, +- {"memhash64", funcTag, 125}, +- {"memhash128", funcTag, 125}, +- {"f32hash", funcTag, 125}, +- {"f64hash", funcTag, 125}, +- {"c64hash", funcTag, 125}, +- {"c128hash", funcTag, 125}, +- {"strhash", funcTag, 125}, +- {"interhash", funcTag, 125}, +- {"nilinterhash", funcTag, 125}, +- {"int64div", funcTag, 126}, +- {"uint64div", funcTag, 127}, +- {"int64mod", funcTag, 126}, +- {"uint64mod", funcTag, 127}, +- {"float64toint64", funcTag, 128}, +- {"float64touint64", funcTag, 129}, +- {"float64touint32", funcTag, 130}, +- {"int64tofloat64", funcTag, 131}, +- {"uint64tofloat64", funcTag, 132}, +- {"uint32tofloat64", funcTag, 133}, +- {"complex128div", funcTag, 134}, +- {"getcallerpc", funcTag, 135}, +- {"getcallersp", funcTag, 135}, ++ {"unsafeslicecheckptr", funcTag, 117}, ++ {"memmove", funcTag, 118}, ++ {"memclrNoHeapPointers", funcTag, 119}, ++ {"memclrHasPointers", funcTag, 119}, ++ {"memequal", funcTag, 120}, ++ {"memequal0", funcTag, 121}, ++ {"memequal8", funcTag, 121}, ++ {"memequal16", funcTag, 121}, ++ {"memequal32", funcTag, 121}, ++ {"memequal64", funcTag, 121}, ++ {"memequal128", funcTag, 121}, ++ {"f32equal", funcTag, 122}, ++ {"f64equal", funcTag, 122}, ++ {"c64equal", funcTag, 122}, ++ {"c128equal", funcTag, 122}, ++ {"strequal", funcTag, 122}, ++ {"interequal", funcTag, 122}, ++ {"nilinterequal", funcTag, 122}, ++ {"memhash", funcTag, 123}, ++ {"memhash0", funcTag, 124}, ++ {"memhash8", funcTag, 124}, ++ {"memhash16", funcTag, 124}, ++ {"memhash32", funcTag, 124}, ++ {"memhash64", funcTag, 124}, ++ {"memhash128", funcTag, 124}, ++ {"f32hash", funcTag, 124}, ++ {"f64hash", funcTag, 124}, ++ {"c64hash", funcTag, 124}, ++ {"c128hash", funcTag, 124}, ++ {"strhash", funcTag, 124}, ++ {"interhash", funcTag, 124}, ++ {"nilinterhash", funcTag, 124}, ++ {"int64div", funcTag, 125}, ++ {"uint64div", funcTag, 126}, ++ {"int64mod", funcTag, 125}, ++ {"uint64mod", funcTag, 126}, ++ {"float64toint64", funcTag, 127}, ++ {"float64touint64", funcTag, 128}, ++ {"float64touint32", funcTag, 129}, ++ {"int64tofloat64", funcTag, 130}, ++ {"uint64tofloat64", funcTag, 131}, ++ {"uint32tofloat64", funcTag, 132}, ++ {"complex128div", funcTag, 133}, ++ {"getcallerpc", funcTag, 134}, ++ {"getcallersp", funcTag, 134}, + {"racefuncenter", funcTag, 31}, + {"racefuncexit", funcTag, 9}, + {"raceread", funcTag, 31}, + {"racewrite", funcTag, 31}, +- {"racereadrange", funcTag, 136}, +- {"racewriterange", funcTag, 136}, +- {"msanread", funcTag, 136}, +- {"msanwrite", funcTag, 136}, +- {"msanmove", funcTag, 137}, +- {"checkptrAlignment", funcTag, 138}, +- {"checkptrArithmetic", funcTag, 140}, +- {"libfuzzerTraceCmp1", funcTag, 141}, +- {"libfuzzerTraceCmp2", funcTag, 142}, +- {"libfuzzerTraceCmp4", funcTag, 143}, +- {"libfuzzerTraceCmp8", funcTag, 144}, +- {"libfuzzerTraceConstCmp1", funcTag, 141}, +- {"libfuzzerTraceConstCmp2", funcTag, 142}, +- {"libfuzzerTraceConstCmp4", funcTag, 143}, +- {"libfuzzerTraceConstCmp8", funcTag, 144}, ++ {"racereadrange", funcTag, 135}, ++ {"racewriterange", funcTag, 135}, ++ {"msanread", funcTag, 135}, ++ {"msanwrite", funcTag, 135}, ++ {"msanmove", funcTag, 136}, ++ {"checkptrAlignment", funcTag, 137}, ++ {"checkptrArithmetic", funcTag, 139}, ++ {"libfuzzerTraceCmp1", funcTag, 140}, ++ {"libfuzzerTraceCmp2", funcTag, 141}, ++ {"libfuzzerTraceCmp4", funcTag, 142}, ++ {"libfuzzerTraceCmp8", funcTag, 143}, ++ {"libfuzzerTraceConstCmp1", funcTag, 140}, ++ {"libfuzzerTraceConstCmp2", funcTag, 141}, ++ {"libfuzzerTraceConstCmp4", funcTag, 142}, ++ {"libfuzzerTraceConstCmp8", funcTag, 143}, + {"x86HasPOPCNT", varTag, 6}, + {"x86HasSSE41", varTag, 6}, + {"x86HasFMA", varTag, 6}, +@@ -224,7 +222,7 @@ func params(tlist ...*types.Type) []*types.Field { + } + + func runtimeTypes() []*types.Type { +- var typs [145]*types.Type ++ var typs [144]*types.Type + typs[0] = types.ByteType + typs[1] = types.NewPtr(typs[0]) + typs[2] = types.Types[types.TANY] +@@ -342,33 +340,32 @@ func runtimeTypes() []*types.Type { + typs[114] = newSig(params(typs[1], typs[15], typs[15], typs[7]), params(typs[7])) + typs[115] = types.NewSlice(typs[2]) + typs[116] = newSig(params(typs[1], typs[115], typs[15]), params(typs[115])) +- typs[117] = newSig(params(typs[1], typs[7], typs[15]), nil) +- typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil) +- typs[119] = newSig(params(typs[3], typs[3], typs[5]), nil) +- typs[120] = newSig(params(typs[7], typs[5]), nil) +- typs[121] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) +- typs[122] = newSig(params(typs[3], typs[3]), params(typs[6])) +- typs[123] = newSig(params(typs[7], typs[7]), params(typs[6])) +- typs[124] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) +- typs[125] = newSig(params(typs[7], typs[5]), params(typs[5])) +- typs[126] = newSig(params(typs[22], typs[22]), params(typs[22])) +- typs[127] = newSig(params(typs[24], typs[24]), params(typs[24])) +- typs[128] = newSig(params(typs[20]), params(typs[22])) +- typs[129] = newSig(params(typs[20]), params(typs[24])) +- typs[130] = newSig(params(typs[20]), params(typs[60])) +- typs[131] = newSig(params(typs[22]), params(typs[20])) +- typs[132] = newSig(params(typs[24]), params(typs[20])) +- typs[133] = newSig(params(typs[60]), params(typs[20])) +- typs[134] = newSig(params(typs[26], typs[26]), params(typs[26])) +- typs[135] = newSig(nil, params(typs[5])) +- typs[136] = newSig(params(typs[5], typs[5]), nil) +- typs[137] = newSig(params(typs[5], typs[5], typs[5]), nil) +- typs[138] = newSig(params(typs[7], typs[1], typs[5]), nil) +- typs[139] = types.NewSlice(typs[7]) +- typs[140] = newSig(params(typs[7], typs[139]), nil) +- typs[141] = newSig(params(typs[64], typs[64]), nil) +- typs[142] = newSig(params(typs[58], typs[58]), nil) +- typs[143] = newSig(params(typs[60], typs[60]), nil) +- typs[144] = newSig(params(typs[24], typs[24]), nil) ++ typs[117] = newSig(params(typs[1], typs[7], typs[22]), nil) ++ typs[118] = newSig(params(typs[3], typs[3], typs[5]), nil) ++ typs[119] = newSig(params(typs[7], typs[5]), nil) ++ typs[120] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6])) ++ typs[121] = newSig(params(typs[3], typs[3]), params(typs[6])) ++ typs[122] = newSig(params(typs[7], typs[7]), params(typs[6])) ++ typs[123] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5])) ++ typs[124] = newSig(params(typs[7], typs[5]), params(typs[5])) ++ typs[125] = newSig(params(typs[22], typs[22]), params(typs[22])) ++ typs[126] = newSig(params(typs[24], typs[24]), params(typs[24])) ++ typs[127] = newSig(params(typs[20]), params(typs[22])) ++ typs[128] = newSig(params(typs[20]), params(typs[24])) ++ typs[129] = newSig(params(typs[20]), params(typs[60])) ++ typs[130] = newSig(params(typs[22]), params(typs[20])) ++ typs[131] = newSig(params(typs[24]), params(typs[20])) ++ typs[132] = newSig(params(typs[60]), params(typs[20])) ++ typs[133] = newSig(params(typs[26], typs[26]), params(typs[26])) ++ typs[134] = newSig(nil, params(typs[5])) ++ typs[135] = newSig(params(typs[5], typs[5]), nil) ++ typs[136] = newSig(params(typs[5], typs[5], typs[5]), nil) ++ typs[137] = newSig(params(typs[7], typs[1], typs[5]), nil) ++ typs[138] = types.NewSlice(typs[7]) ++ typs[139] = newSig(params(typs[7], typs[138]), nil) ++ typs[140] = newSig(params(typs[64], typs[64]), nil) ++ typs[141] = newSig(params(typs[58], typs[58]), nil) ++ typs[142] = newSig(params(typs[60], typs[60]), nil) ++ typs[143] = newSig(params(typs[24], typs[24]), nil) + return typs[:] + } +diff --git a/src/cmd/compile/internal/typecheck/builtin/runtime.go b/src/cmd/compile/internal/typecheck/builtin/runtime.go +index 2b29ea3c08..bd45258058 100644 +--- a/src/cmd/compile/internal/typecheck/builtin/runtime.go ++++ b/src/cmd/compile/internal/typecheck/builtin/runtime.go +@@ -183,8 +183,6 @@ func makeslice(typ *byte, len int, cap int) unsafe.Pointer + func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer + func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer + func growslice(typ *byte, old []any, cap int) (ary []any) +-func unsafeslice(typ *byte, ptr unsafe.Pointer, len int) +-func unsafeslice64(typ *byte, ptr unsafe.Pointer, len int64) + func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64) + + func memmove(to *any, frm *any, length uintptr) +diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go +index 14efc05e32..2843d468e5 100644 +--- a/src/cmd/compile/internal/walk/builtin.go ++++ b/src/cmd/compile/internal/walk/builtin.go +@@ -656,27 +656,14 @@ func walkRecover(nn *ir.CallExpr, init *ir.Nodes) ir.Node { + func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { + ptr := safeExpr(n.X, init) + len := safeExpr(n.Y, init) +- +- fnname := "unsafeslice64" + lenType := types.Types[types.TINT64] +- +- // Type checking guarantees that TIDEAL len/cap are positive and fit in an int. +- // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT +- // will be handled by the negative range checks in unsafeslice during runtime. ++ t := n.Type() + if ir.ShouldCheckPtr(ir.CurFunc, 1) { +- fnname = "unsafeslicecheckptr" +- // for simplicity, unsafeslicecheckptr always uses int64 ++ fn := typecheck.LookupRuntime("unsafeslicecheckptr") ++ init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), typecheck.Conv(len, lenType))) + } else if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() { +- fnname = "unsafeslice" + lenType = types.Types[types.TINT] + } +- +- t := n.Type() +- +- // Call runtime.unsafeslice{,64,checkptr} to check ptr and len. +- fn := typecheck.LookupRuntime(fnname) +- init.Append(mkcall1(fn, nil, init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), typecheck.Conv(len, lenType))) +- + h := ir.NewSliceHeaderExpr(n.Pos(), t, + typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]), + typecheck.Conv(len, types.Types[types.TINT]), +diff --git a/test/unsafebuiltins.go b/test/unsafebuiltins.go +index 4c940aa855..d613088827 100644 +--- a/test/unsafebuiltins.go ++++ b/test/unsafebuiltins.go +@@ -6,10 +6,7 @@ + + package main + +-import ( +- "math" +- "unsafe" +-) ++import "unsafe" + + const maxUintptr = 1 << (8 * unsafe.Sizeof(uintptr(0))) + +@@ -29,24 +26,6 @@ func main() { + assert(&s[0] == &p[0]) + assert(len(s) == len(p)) + assert(cap(s) == len(p)) +- +- // nil pointer with zero length returns nil +- assert(unsafe.Slice((*int)(nil), 0) == nil) +- +- // nil pointer with positive length panics +- mustPanic(func() { _ = unsafe.Slice((*int)(nil), 1) }) +- +- // negative length +- var neg int = -1 +- mustPanic(func() { _ = unsafe.Slice(new(byte), neg) }) +- +- // length too large +- var tooBig uint64 = math.MaxUint64 +- mustPanic(func() { _ = unsafe.Slice(new(byte), tooBig) }) +- +- // size overflows address space +- mustPanic(func() { _ = unsafe.Slice(new(uint64), maxUintptr/8) }) +- mustPanic(func() { _ = unsafe.Slice(new(uint64), maxUintptr/8+1) }) + } + } + +@@ -55,10 +34,3 @@ func assert(ok bool) { + panic("FAIL") + } + } +- +-func mustPanic(f func()) { +- defer func() { +- assert(recover() != nil) +- }() +- f() +-} +-- +2.33.0 + -- cgit v1.2.3-59-g8ed1b