Source file src/internal/abi/escape.go
1 // Copyright 2024 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package abi 6 7 import "unsafe" 8 9 // NoEscape hides the pointer p from escape analysis, preventing it 10 // from escaping to the heap. It compiles down to nothing. 11 // 12 // WARNING: This is very subtle to use correctly. The caller must 13 // ensure that it's truly safe for p to not escape to the heap by 14 // maintaining runtime pointer invariants (for example, that globals 15 // and the heap may not generally point into a stack). 16 // 17 //go:nosplit 18 //go:nocheckptr 19 func NoEscape(p unsafe.Pointer) unsafe.Pointer { 20 x := uintptr(p) 21 return unsafe.Pointer(x ^ 0) 22 } 23 24 var alwaysFalse bool 25 var escapeSink any 26 27 // Escape forces any pointers in x to escape to the heap. 28 func Escape[T any](x T) T { 29 if alwaysFalse { 30 escapeSink = x 31 } 32 return x 33 } 34 35 // EscapeNonString forces v to be on the heap, if v contains a 36 // non-string pointer. 37 // 38 // This is used in hash/maphash.Comparable. We cannot hash pointers 39 // to local variables on stack, as their addresses might change on 40 // stack growth. Strings are okay as the hash depends on only the 41 // content, not the pointer. 42 // 43 // This is essentially 44 // 45 // if hasNonStringPointers(T) { Escape(v) } 46 // 47 // Implemented as a compiler intrinsic. 48 func EscapeNonString[T any](v T) { panic("intrinsic") } 49 50 // EscapeToResultNonString models a data flow edge from v to the result, 51 // if v contains a non-string pointer. If v contains only string pointers, 52 // it returns a copy of v, but is not modeled as a data flow edge 53 // from the escape analysis's perspective. 54 // 55 // This is used in unique.clone, to model the data flow edge on the 56 // value with strings excluded, because strings are cloned (by 57 // content). 58 // 59 // TODO: probably we should define this as a intrinsic and EscapeNonString 60 // could just be "heap = EscapeToResultNonString(v)". This way we can model 61 // an edge to the result but not necessarily heap. 62 func EscapeToResultNonString[T any](v T) T { 63 EscapeNonString(v) 64 return *(*T)(NoEscape(unsafe.Pointer(&v))) 65 } 66