pointer.mx raw

   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