diff options
author | Jamie Liu <jamieliu@google.com> | 2021-02-17 17:39:24 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-02-17 17:41:10 -0800 |
commit | f051ec64639b83faabcfe766ff078072def3c2aa (patch) | |
tree | 892c0fc2f4fd4138299c3c0d5a5836a940a670b5 /pkg/gohacks | |
parent | 4bc7daf91a0d9102fa477b199964e7db45066da1 (diff) |
Add gohacks.Slice/StringHeader.
See https://github.com/golang/go/issues/19367 for rationale. Note that the
upstream decision arrived at in that thread, while useful for some of our use
cases, doesn't account for all of our SliceHeader use cases (we often use
SliceHeader to extract pointers from slices in a way that avoids bounds
checking and/or handles nil slices correctly) and also doesn't exist yet.
PiperOrigin-RevId: 358071574
Diffstat (limited to 'pkg/gohacks')
-rw-r--r-- | pkg/gohacks/gohacks_unsafe.go | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/pkg/gohacks/gohacks_unsafe.go b/pkg/gohacks/gohacks_unsafe.go index aad675172..d26c1ac05 100644 --- a/pkg/gohacks/gohacks_unsafe.go +++ b/pkg/gohacks/gohacks_unsafe.go @@ -12,14 +12,35 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build go1.13 +// +build !go1.17 + +// Check type signatures when updating Go version. + // Package gohacks contains utilities for subverting the Go compiler. package gohacks import ( - "reflect" "unsafe" ) +// SliceHeader is equivalent to reflect.SliceHeader, but represents the pointer +// to the underlying array as unsafe.Pointer rather than uintptr, allowing +// SliceHeaders to be directly converted to slice objects. +type SliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} + +// StringHeader is equivalent to reflect.StringHeader, but represents the +// pointer to the underlying array as unsafe.Pointer rather than uintptr, +// allowing StringHeaders to be directly converted to strings. +type StringHeader struct { + Data unsafe.Pointer + Len int +} + // Noescape hides a pointer from escape analysis. Noescape is the identity // function but escape analysis doesn't think the output depends on the input. // Noescape is inlined and currently compiles down to zero instructions. @@ -36,22 +57,21 @@ func Noescape(p unsafe.Pointer) unsafe.Pointer { // ImmutableBytesFromString is equivalent to []byte(s), except that it uses the // same memory backing s instead of making a heap-allocated copy. This is only // valid if the returned slice is never mutated. -func ImmutableBytesFromString(s string) []byte { - shdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) - var bs []byte - bshdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) +func ImmutableBytesFromString(s string) (bs []byte) { + shdr := (*StringHeader)(unsafe.Pointer(&s)) + bshdr := (*SliceHeader)(unsafe.Pointer(&bs)) bshdr.Data = shdr.Data bshdr.Len = shdr.Len bshdr.Cap = shdr.Len - return bs + return } // StringFromImmutableBytes is equivalent to string(bs), except that it uses // the same memory backing bs instead of making a heap-allocated copy. This is // only valid if bs is never mutated after StringFromImmutableBytes returns. func StringFromImmutableBytes(bs []byte) string { - // This is cheaper than messing with reflect.StringHeader and - // reflect.SliceHeader, which as of this writing produces many dead stores - // of zeroes. Compare strings.Builder.String(). + // This is cheaper than messing with StringHeader and SliceHeader, which as + // of this writing produces many dead stores of zeroes. Compare + // strings.Builder.String(). return *(*string)(unsafe.Pointer(&bs)) } |