inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/gohacks/gohacks_unsafe.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:build go1.13 && !go1.19
    16  // +build go1.13,!go1.19
    17  
    18  // //go:linkname directives type-checked by checklinkname. Any other
    19  // non-linkname assumptions outside the Go 1 compatibility guarantee should
    20  // have an accompanied vet check or version guard build tag.
    21  
    22  // Check type signatures and Noescape when updating Go version.
    23  //
    24  // TODO(b/165820485): add these checks to checklinkname.
    25  
    26  // Package gohacks contains utilities for subverting the Go compiler.
    27  package gohacks
    28  
    29  import (
    30  	"unsafe"
    31  )
    32  
    33  // SliceHeader is equivalent to reflect.SliceHeader, but represents the pointer
    34  // to the underlying array as unsafe.Pointer rather than uintptr, allowing
    35  // SliceHeaders to be directly converted to slice objects.
    36  type SliceHeader struct {
    37  	Data unsafe.Pointer
    38  	Len  int
    39  	Cap  int
    40  }
    41  
    42  // StringHeader is equivalent to reflect.StringHeader, but represents the
    43  // pointer to the underlying array as unsafe.Pointer rather than uintptr,
    44  // allowing StringHeaders to be directly converted to strings.
    45  type StringHeader struct {
    46  	Data unsafe.Pointer
    47  	Len  int
    48  }
    49  
    50  // Noescape hides a pointer from escape analysis. Noescape is the identity
    51  // function but escape analysis doesn't think the output depends on the input.
    52  // Noescape is inlined and currently compiles down to zero instructions.
    53  // USE CAREFULLY!
    54  //
    55  // (Noescape is copy/pasted from Go's runtime/stubs.go:noescape().)
    56  //
    57  //go:nosplit
    58  func Noescape(p unsafe.Pointer) unsafe.Pointer {
    59  	x := uintptr(p)
    60  	return unsafe.Pointer(x ^ 0)
    61  }
    62  
    63  // ImmutableBytesFromString is equivalent to []byte(s), except that it uses the
    64  // same memory backing s instead of making a heap-allocated copy. This is only
    65  // valid if the returned slice is never mutated.
    66  func ImmutableBytesFromString(s string) (bs []byte) {
    67  	shdr := (*StringHeader)(unsafe.Pointer(&s))
    68  	bshdr := (*SliceHeader)(unsafe.Pointer(&bs))
    69  	bshdr.Data = shdr.Data
    70  	bshdr.Len = shdr.Len
    71  	bshdr.Cap = shdr.Len
    72  	return
    73  }
    74  
    75  // StringFromImmutableBytes is equivalent to string(bs), except that it uses
    76  // the same memory backing bs instead of making a heap-allocated copy. This is
    77  // only valid if bs is never mutated after StringFromImmutableBytes returns.
    78  func StringFromImmutableBytes(bs []byte) string {
    79  	// This is cheaper than messing with StringHeader and SliceHeader, which as
    80  	// of this writing produces many dead stores of zeroes. Compare
    81  	// strings.Builder.String().
    82  	return *(*string)(unsafe.Pointer(&bs))
    83  }
    84  
    85  // Note that go:linkname silently doesn't work if the local name is exported,
    86  // necessitating an indirection for exported functions.
    87  
    88  // Memmove is runtime.memmove, exported for SeqAtomicLoad/SeqAtomicTryLoad<T>.
    89  //
    90  //go:nosplit
    91  func Memmove(to, from unsafe.Pointer, n uintptr) {
    92  	memmove(to, from, n)
    93  }
    94  
    95  //go:linkname memmove runtime.memmove
    96  //go:noescape
    97  func memmove(to, from unsafe.Pointer, n uintptr)