github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/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 // +build go1.13 16 // +build !go1.18 17 18 // Check type signatures when updating Go version. 19 20 // Package gohacks contains utilities for subverting the Go compiler. 21 package gohacks 22 23 import ( 24 "unsafe" 25 ) 26 27 // SliceHeader is equivalent to reflect.SliceHeader, but represents the pointer 28 // to the underlying array as unsafe.Pointer rather than uintptr, allowing 29 // SliceHeaders to be directly converted to slice objects. 30 type SliceHeader struct { 31 Data unsafe.Pointer 32 Len int 33 Cap int 34 } 35 36 // StringHeader is equivalent to reflect.StringHeader, but represents the 37 // pointer to the underlying array as unsafe.Pointer rather than uintptr, 38 // allowing StringHeaders to be directly converted to strings. 39 type StringHeader struct { 40 Data unsafe.Pointer 41 Len int 42 } 43 44 // Noescape hides a pointer from escape analysis. Noescape is the identity 45 // function but escape analysis doesn't think the output depends on the input. 46 // Noescape is inlined and currently compiles down to zero instructions. 47 // USE CAREFULLY! 48 // 49 // (Noescape is copy/pasted from Go's runtime/stubs.go:noescape().) 50 // 51 //go:nosplit 52 func Noescape(p unsafe.Pointer) unsafe.Pointer { 53 x := uintptr(p) 54 return unsafe.Pointer(x ^ 0) 55 } 56 57 // ImmutableBytesFromString is equivalent to []byte(s), except that it uses the 58 // same memory backing s instead of making a heap-allocated copy. This is only 59 // valid if the returned slice is never mutated. 60 func ImmutableBytesFromString(s string) (bs []byte) { 61 shdr := (*StringHeader)(unsafe.Pointer(&s)) 62 bshdr := (*SliceHeader)(unsafe.Pointer(&bs)) 63 bshdr.Data = shdr.Data 64 bshdr.Len = shdr.Len 65 bshdr.Cap = shdr.Len 66 return 67 } 68 69 // StringFromImmutableBytes is equivalent to string(bs), except that it uses 70 // the same memory backing bs instead of making a heap-allocated copy. This is 71 // only valid if bs is never mutated after StringFromImmutableBytes returns. 72 func StringFromImmutableBytes(bs []byte) string { 73 // This is cheaper than messing with StringHeader and SliceHeader, which as 74 // of this writing produces many dead stores of zeroes. Compare 75 // strings.Builder.String(). 76 return *(*string)(unsafe.Pointer(&bs)) 77 } 78 79 // Note that go:linkname silently doesn't work if the local name is exported, 80 // necessitating an indirection for exported functions. 81 82 // Memmove is runtime.memmove, exported for SeqAtomicLoad/SeqAtomicTryLoad<T>. 83 // 84 //go:nosplit 85 func Memmove(to, from unsafe.Pointer, n uintptr) { 86 memmove(to, from, n) 87 } 88 89 //go:linkname memmove runtime.memmove 90 //go:noescape 91 func memmove(to, from unsafe.Pointer, n uintptr)