| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| /* |
| The weak package is a package for managing weak pointers. |
| |
| Weak pointers are pointers that explicitly do not keep a value live and |
| must be queried for a regular Go pointer. |
| The result of such a query may be observed as nil at any point after a |
| weakly-pointed-to object becomes eligible for reclamation by the garbage |
| collector. |
| More specifically, weak pointers become nil as soon as the garbage collector |
| identifies that the object is unreachable, before it is made reachable |
| again by a finalizer. |
| In terms of the C# language, these semantics are roughly equivalent to the |
| the semantics of "short" weak references. |
| In terms of the Java language, these semantics are roughly equivalent to the |
| semantics of the WeakReference type. |
| |
| Using go:linkname to access this package and the functions it references |
| is explicitly forbidden by the toolchain because the semantics of this |
| package have not gone through the proposal process. By exposing this |
| functionality, we risk locking in the existing semantics due to Hyrum's Law. |
| |
| If you believe you have a good use-case for weak references not already |
| covered by the standard library, file a proposal issue at |
| https://github.com/golang/go/issues instead of relying on this package. |
| */ |
| package weak |
| |
| import ( |
| "internal/abi" |
| "runtime" |
| "unsafe" |
| ) |
| |
| // Pointer is a weak pointer to a value of type T. |
| // |
| // This value is comparable is guaranteed to compare equal if the pointers |
| // that they were created from compare equal. This property is retained even |
| // after the object referenced by the pointer used to create a weak reference |
| // is reclaimed. |
| // |
| // If multiple weak pointers are made to different offsets within same object |
| // (for example, pointers to different fields of the same struct), those pointers |
| // will not compare equal. |
| // If a weak pointer is created from an object that becomes reachable again due |
| // to a finalizer, that weak pointer will not compare equal with weak pointers |
| // created before it became unreachable. |
| type Pointer[T any] struct { |
| u unsafe.Pointer |
| } |
| |
| // Make creates a weak pointer from a strong pointer to some value of type T. |
| func Make[T any](ptr *T) Pointer[T] { |
| // Explicitly force ptr to escape to the heap. |
| ptr = abi.Escape(ptr) |
| |
| var u unsafe.Pointer |
| if ptr != nil { |
| u = runtime_registerWeakPointer(unsafe.Pointer(ptr)) |
| } |
| runtime.KeepAlive(ptr) |
| return Pointer[T]{u} |
| } |
| |
| // Strong creates a strong pointer from the weak pointer. |
| // Returns nil if the original value for the weak pointer was reclaimed by |
| // the garbage collector. |
| // If a weak pointer points to an object with a finalizer, then Strong will |
| // return nil as soon as the object's finalizer is queued for execution. |
| func (p Pointer[T]) Strong() *T { |
| return (*T)(runtime_makeStrongFromWeak(p.u)) |
| } |
| |
| // Implemented in runtime. |
| |
| //go:linkname runtime_registerWeakPointer |
| func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer |
| |
| //go:linkname runtime_makeStrongFromWeak |
| func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer |