Source file src/weak/pointer.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 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  

View as plain text