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)