Skip to content

Commit a65f1a4

Browse files
mknyszekgopherbot
authored andcommitted
weak: move internal/weak to weak, and update according to proposal
The updates are: - API documentation changes. - Removal of the old package documentation discouraging linkname. - Addition of new package documentation with some advice. - Renaming of weak.Pointer.Strong -> weak.Pointer.Value. Fixes #67552. Change-Id: Ifad7e629b6d339dacaf2ca37b459d7f903e31bf8 Reviewed-on: https://go-review.googlesource.com/c/go/+/628455 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Carlos Amedee <[email protected]> Auto-Submit: Michael Knyszek <[email protected]>
1 parent 5e82cba commit a65f1a4

File tree

15 files changed

+129
-110
lines changed

15 files changed

+129
-110
lines changed

api/next/67552.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pkg weak, func Make[$0 interface{}](*$0) Pointer[$0] #67552
2+
pkg weak, method (Pointer[$0]) Value() *$0 #67552
3+
pkg weak, type Pointer[$0 interface{}] struct #67552

doc/next/6-stdlib/1-weak.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
### New weak package
2+
3+
The new [weak](/pkg/weak) package provides weak pointers.
4+
5+
Weak pointers are a low-level primitive provided to enable the
6+
creation of memory-efficient structures, such as weak maps for
7+
associating values, canonicalization maps for anything not
8+
covered by package [unique](/pkg/unique), and various kinds
9+
of caches.
10+
For supporting these use-cases, this release also provides
11+
[runtime.AddCleanup](/pkg/runtime#AddCleanup) and
12+
[maphash.Comparable](/pkg/maphash#Comparable).
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!-- This is a new package; covered in 6-stdlib/1-weak.md. -->

src/cmd/link/internal/loader/loader.go

-3
Original file line numberDiff line numberDiff line change
@@ -2336,9 +2336,6 @@ var blockedLinknames = map[string][]string{
23362336
// coroutines
23372337
"runtime.coroswitch": {"iter"},
23382338
"runtime.newcoro": {"iter"},
2339-
// weak references
2340-
"internal/weak.runtime_registerWeakPointer": {"internal/weak"},
2341-
"internal/weak.runtime_makeStrongFromWeak": {"internal/weak"},
23422339
// fips info
23432340
"go:fipsinfo": {"crypto/internal/fips/check"},
23442341
}

src/go/build/deps_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ var depsRules = `
9696
< internal/runtime/maps
9797
< runtime
9898
< sync/atomic
99-
< internal/weak
10099
< internal/sync
100+
< weak
101101
< sync
102102
< internal/bisect
103103
< internal/godebug

src/go/doc/comment/std.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/internal/weak/pointer.go

-83
This file was deleted.

src/runtime/gc_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"fmt"
99
"internal/asan"
1010
"internal/testenv"
11-
"internal/weak"
1211
"math/bits"
1312
"math/rand"
1413
"os"
@@ -22,6 +21,7 @@ import (
2221
"testing"
2322
"time"
2423
"unsafe"
24+
"weak"
2525
)
2626

2727
func TestGcSys(t *testing.T) {
@@ -826,7 +826,7 @@ func TestWeakToStrongMarkTermination(t *testing.T) {
826826

827827
// Start a GC, and wait a little bit to get something spinning in mark termination.
828828
// Simultaneously, fire off another goroutine to disable spinning. If everything's
829-
// working correctly, then weak.Strong will block, so we need to make sure something
829+
// working correctly, then weak.Value will block, so we need to make sure something
830830
// prevents the GC from continuing to spin.
831831
done := make(chan struct{})
832832
go func() {
@@ -847,7 +847,7 @@ func TestWeakToStrongMarkTermination(t *testing.T) {
847847
wg.Add(1)
848848
go func() {
849849
defer wg.Done()
850-
wp.Strong()
850+
wp.Value()
851851
}()
852852
}
853853

src/runtime/mgcsweep.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
564564
}
565565
if hasFinAndRevived {
566566
// Pass 2: queue all finalizers and clear any weak handles. Weak handles are cleared
567-
// before finalization as specified by the internal/weak package. See the documentation
567+
// before finalization as specified by the weak package. See the documentation
568568
// for that package for more details.
569569
for siter.valid() && uintptr(siter.s.offset) < endOffset {
570570
// Find the exact byte for which the special was setup

src/runtime/mheap.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -2092,12 +2092,12 @@ type specialWeakHandle struct {
20922092
handle *atomic.Uintptr
20932093
}
20942094

2095-
//go:linkname internal_weak_runtime_registerWeakPointer internal/weak.runtime_registerWeakPointer
2095+
//go:linkname internal_weak_runtime_registerWeakPointer weak.runtime_registerWeakPointer
20962096
func internal_weak_runtime_registerWeakPointer(p unsafe.Pointer) unsafe.Pointer {
20972097
return unsafe.Pointer(getOrAddWeakHandle(unsafe.Pointer(p)))
20982098
}
20992099

2100-
//go:linkname internal_weak_runtime_makeStrongFromWeak internal/weak.runtime_makeStrongFromWeak
2100+
//go:linkname internal_weak_runtime_makeStrongFromWeak weak.runtime_makeStrongFromWeak
21012101
func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer {
21022102
handle := (*atomic.Uintptr)(u)
21032103

src/unique/handle.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ package unique
77
import (
88
"internal/abi"
99
isync "internal/sync"
10-
"internal/weak"
1110
"runtime"
1211
"sync"
1312
"unsafe"
13+
"weak"
1414
)
1515

1616
var zero uintptr
@@ -76,7 +76,7 @@ func Make[T comparable](value T) Handle[T] {
7676
}
7777
// Now that we're sure there's a value in the map, let's
7878
// try to get the pointer we need out of it.
79-
ptr = wp.Strong()
79+
ptr = wp.Value()
8080
if ptr != nil {
8181
break
8282
}
@@ -132,7 +132,7 @@ func addUniqueMap[T comparable](typ *abi.Type) *uniqueMap[T] {
132132
// Delete all the entries whose weak references are nil and clean up
133133
// deleted entries.
134134
m.All()(func(key T, wp weak.Pointer[T]) bool {
135-
if wp.Strong() == nil {
135+
if wp.Value() == nil {
136136
m.CompareAndDelete(key, wp)
137137
}
138138
return true

src/unique/handle_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func checkMapsFor[T comparable](t *testing.T, value T) {
114114
if !ok {
115115
return
116116
}
117-
if wp.Strong() != nil {
117+
if wp.Value() != nil {
118118
t.Errorf("value %v still referenced a handle (or tiny block?) ", value)
119119
return
120120
}

src/weak/doc.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
/*
6+
Package weak provides weak pointers with the goal of memory efficiency.
7+
The primary use-cases for weak pointers are for implementing caches,
8+
canonicalization maps (like the unique package), and for tying together
9+
the lifetimes of separate values.
10+
11+
## Advice
12+
13+
This package is intended to target niche use-cases like the unique
14+
package, not as a general replacement for regular Go pointers, maps,
15+
etc.
16+
Misuse of the structures in this package will generate unexpected and
17+
hard-to-reproduce bugs.
18+
Using the facilities in this package to try and resolve out-of-memory
19+
issues and/or memory leaks is very likely the wrong answer.
20+
21+
The structures in this package are intended to be an implementation
22+
detail of the package they are used by (again, see the unique package).
23+
Avoid exposing weak structures across API boundaries, since that exposes
24+
users of your package to the subtleties of this package.
25+
*/
26+
package weak

src/weak/pointer.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
// Two Pointer values compare equal if the pointers
16+
// that they were created from compare equal. This property is retained even
17+
// after the object referenced by the pointer used to create a weak reference
18+
// is reclaimed.
19+
//
20+
// If multiple weak pointers are made to different offsets within same object
21+
// (for example, pointers to different fields of the same struct), those pointers
22+
// will not compare equal.
23+
// If a weak pointer is created from an object that becomes unreachable, but is
24+
// then resurrected due to a finalizer, that weak pointer will not compare equal
25+
// with weak pointers created after resurrection.
26+
//
27+
// Calling Make with a nil pointer returns a weak pointer whose Value method
28+
// always returns nil. The zero value of a Pointer behaves as if it was created
29+
// by passing nil to Make and compares equal with such pointers.
30+
type Pointer[T any] struct {
31+
u unsafe.Pointer
32+
}
33+
34+
// Make creates a weak pointer from a strong pointer to some value of type T.
35+
func Make[T any](ptr *T) Pointer[T] {
36+
// Explicitly force ptr to escape to the heap.
37+
ptr = abi.Escape(ptr)
38+
39+
var u unsafe.Pointer
40+
if ptr != nil {
41+
u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
42+
}
43+
runtime.KeepAlive(ptr)
44+
return Pointer[T]{u}
45+
}
46+
47+
// Value returns the original pointer used to create the weak pointer.
48+
// It returns nil if the value pointed to by the original pointer was reclaimed by
49+
// the garbage collector.
50+
// If a weak pointer points to an object with a finalizer, then Value will
51+
// return nil as soon as the object's finalizer is queued for execution.
52+
func (p Pointer[T]) Value() *T {
53+
return (*T)(runtime_makeStrongFromWeak(p.u))
54+
}
55+
56+
// Implemented in runtime.
57+
58+
//go:linkname runtime_registerWeakPointer
59+
func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer
60+
61+
//go:linkname runtime_makeStrongFromWeak
62+
func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer

0 commit comments

Comments
 (0)