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 weak
6 7 import (
8 "internal/abi"
9 "runtime"
10 "unsafe"
11 )
12 13 // Pointer is a weak pointer to a value of type T.
14 //
15 // Just like regular pointers, Pointer may reference any part of an
16 // object, such as a field of a struct or an element of an array.
17 // Objects that are only pointed to by weak pointers are not considered
18 // reachable, and once the object becomes unreachable, [Pointer.Value]
19 // may return nil.
20 //
21 // The primary use-cases for weak pointers are for implementing caches,
22 // canonicalization maps (like the unique package), and for tying together
23 // the lifetimes of separate values (for example, through a map with weak
24 // keys).
25 //
26 // Two Pointer values compare equal if and only if the pointers from which they
27 // were created compare equal.
28 // This property is maintained even after the object referenced by the pointer
29 // used to create a weak reference is reclaimed.
30 // If multiple weak pointers are made to different offsets within the same object
31 // (for example, pointers to different fields of the same struct), those pointers
32 // will not compare equal.
33 // In other words, weak pointers map to objects and offsets within those
34 // objects, not plain addresses.
35 // If a weak pointer is created from an object that becomes unreachable, but is
36 // then resurrected due to a finalizer, that weak pointer will not compare equal
37 // with weak pointers created after the resurrection.
38 //
39 // Calling [Make] with a nil pointer returns a weak pointer whose [Pointer.Value]
40 // always returns nil. The zero value of a Pointer behaves as if it were created
41 // by passing nil to [Make] and compares equal with such pointers.
42 //
43 // [Pointer.Value] is not guaranteed to eventually return nil.
44 // [Pointer.Value] may return nil as soon as the object becomes
45 // unreachable.
46 // Values stored in global variables, or that can be found by tracing
47 // pointers from a global variable, are reachable. A function argument or
48 // receiver may become unreachable at the last point where the function
49 // mentions it. To ensure [Pointer.Value] does not return nil,
50 // pass a pointer to the object to the [runtime.KeepAlive] function after
51 // the last point where the object must remain reachable.
52 //
53 // Note that because [Pointer.Value] is not guaranteed to eventually return
54 // nil, even after an object is no longer referenced, the runtime is allowed to
55 // perform a space-saving optimization that batches objects together in a single
56 // allocation slot. The weak pointer for an unreferenced object in such an
57 // allocation may never become nil if it always exists in the same batch as a
58 // referenced object. Typically, this batching only happens for tiny
59 // (on the order of 16 bytes or less) and pointer-free objects.
60 type Pointer[T any] struct {
61 // Mention T in the type definition to prevent conversions
62 // between Pointer types, like we do for sync/atomic.Pointer.
63 _ [0]*T
64 u unsafe.Pointer
65 }
66 67 // Make creates a weak pointer from a pointer to some value of type T.
68 func Make[T any](ptr *T) Pointer[T] {
69 // Explicitly force ptr to escape to the heap.
70 ptr = abi.Escape(ptr)
71 72 var u unsafe.Pointer
73 if ptr != nil {
74 u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
75 }
76 runtime.KeepAlive(ptr)
77 return Pointer[T]{u: u}
78 }
79 80 // Value returns the original pointer used to create the weak pointer.
81 // It returns nil if the value pointed to by the original pointer was reclaimed by
82 // the garbage collector.
83 // If a weak pointer points to an object with a finalizer, then Value will
84 // return nil as soon as the object's finalizer is queued for execution.
85 func (p Pointer[T]) Value() *T {
86 if p.u == nil {
87 return nil
88 }
89 return (*T)(runtime_makeStrongFromWeak(p.u))
90 }
91 92 // Implemented in runtime.
93 94 //go:linkname runtime_registerWeakPointer
95 func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer
96 97 //go:linkname runtime_makeStrongFromWeak
98 func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer
99