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 always compare equal if the pointers from which they were
    27  // created compare equal. This property is retained even after the
    28  // object referenced by the pointer used to create a weak reference is
    29  // 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  // If a weak pointer is created from an object that becomes unreachable, but is
    34  // then resurrected due to a finalizer, that weak pointer will not compare equal
    35  // with weak pointers created after the resurrection.
    36  //
    37  // Calling [Make] with a nil pointer returns a weak pointer whose [Pointer.Value]
    38  // always returns nil. The zero value of a Pointer behaves as if it were created
    39  // by passing nil to [Make] and compares equal with such pointers.
    40  //
    41  // [Pointer.Value] is not guaranteed to eventually return nil.
    42  // [Pointer.Value] may return nil as soon as the object becomes
    43  // unreachable.
    44  // Values stored in global variables, or that can be found by tracing
    45  // pointers from a global variable, are reachable. A function argument or
    46  // receiver may become unreachable at the last point where the function
    47  // mentions it. To ensure [Pointer.Value] does not return nil,
    48  // pass a pointer to the object to the [runtime.KeepAlive] function after
    49  // the last point where the object must remain reachable.
    50  //
    51  // Note that because [Pointer.Value] is not guaranteed to eventually return
    52  // nil, even after an object is no longer referenced, the runtime is allowed to
    53  // perform a space-saving optimization that batches objects together in a single
    54  // allocation slot. The weak pointer for an unreferenced object in such an
    55  // allocation may never become nil if it always exists in the same batch as a
    56  // referenced object. Typically, this batching only happens for tiny
    57  // (on the order of 16 bytes or less) and pointer-free objects.
    58  type Pointer[T any] struct {
    59  	u unsafe.Pointer
    60  }
    61  
    62  // Make creates a weak pointer from a pointer to some value of type T.
    63  func Make[T any](ptr *T) Pointer[T] {
    64  	// Explicitly force ptr to escape to the heap.
    65  	ptr = abi.Escape(ptr)
    66  
    67  	var u unsafe.Pointer
    68  	if ptr != nil {
    69  		u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
    70  	}
    71  	runtime.KeepAlive(ptr)
    72  	return Pointer[T]{u}
    73  }
    74  
    75  // Value returns the original pointer used to create the weak pointer.
    76  // It returns nil if the value pointed to by the original pointer was reclaimed by
    77  // the garbage collector.
    78  // If a weak pointer points to an object with a finalizer, then Value will
    79  // return nil as soon as the object's finalizer is queued for execution.
    80  func (p Pointer[T]) Value() *T {
    81  	if p.u == nil {
    82  		return nil
    83  	}
    84  	return (*T)(runtime_makeStrongFromWeak(p.u))
    85  }
    86  
    87  // Implemented in runtime.
    88  
    89  //go:linkname runtime_registerWeakPointer
    90  func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer
    91  
    92  //go:linkname runtime_makeStrongFromWeak
    93  func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer
    94  

View as plain text