1 // Copyright 2011 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.
14 type Tintptr
*int // assignable to *int
15 type Tint
int // *Tint implements Tinter, interface{}
19 type Tinter
interface {
23 func TestFinalizerType(t
*testing
.T
) {
24 if runtime
.GOARCH
!= "amd64" {
25 t
.Skipf("Skipping on non-amd64 machine")
27 if runtime
.Compiler
== "gccgo" {
28 t
.Skip("skipping for gccgo")
31 ch
:= make(chan bool, 10)
32 finalize
:= func(x
*int) {
34 t
.Errorf("finalizer %d, want %d", *x
, 97531)
39 var finalizerTests
= []struct {
40 convert
func(*int) any
43 {func(x
*int) any
{ return x
}, func(v
*int) { finalize(v
) }},
44 {func(x
*int) any
{ return Tintptr(x
) }, func(v Tintptr
) { finalize(v
) }},
45 {func(x
*int) any
{ return Tintptr(x
) }, func(v
*int) { finalize(v
) }},
46 {func(x
*int) any
{ return (*Tint
)(x
) }, func(v
*Tint
) { finalize((*int)(v
)) }},
47 {func(x
*int) any
{ return (*Tint
)(x
) }, func(v Tinter
) { finalize((*int)(v
.(*Tint
))) }},
48 // Test case for argument spill slot.
49 // If the spill slot was not counted for the frame size, it will (incorrectly) choose
50 // call32 as the result has (exactly) 32 bytes. When the argument actually spills,
51 // it clobbers the caller's frame (likely the return PC).
52 {func(x
*int) any
{ return x
}, func(v any
) [4]int64 {
53 print() // force spill
59 for i
, tt
:= range finalizerTests
{
60 done
:= make(chan bool, 1)
62 // allocate struct with pointer to avoid hitting tinyalloc.
63 // Otherwise we can't be sure when the allocation will
71 runtime
.SetFinalizer(tt
.convert(v
), tt
.finalizer
)
79 case <-time
.After(time
.Second
* 4):
80 t
.Errorf("#%d: finalizer for type %T didn't run", i
, tt
.finalizer
)
85 type bigValue
struct {
91 func TestFinalizerInterfaceBig(t
*testing
.T
) {
92 if runtime
.GOARCH
!= "amd64" {
93 t
.Skipf("Skipping on non-amd64 machine")
95 if runtime
.Compiler
== "gccgo" {
96 t
.Skip("skipping for gccgo")
99 done
:= make(chan bool, 1)
101 v
:= &bigValue
{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
103 runtime
.SetFinalizer(v
, func(v any
) {
104 i
, ok
:= v
.(*bigValue
)
106 t
.Errorf("finalizer called with type %T, want *bigValue", v
)
109 t
.Errorf("finalizer called with %+v, want %+v", *i
, old
)
120 case <-time
.After(4 * time
.Second
):
121 t
.Errorf("finalizer for type *bigValue didn't run")
128 // Verify we don't crash at least. golang.org/issue/6857
129 func TestFinalizerZeroSizedStruct(t
*testing
.T
) {
132 runtime
.SetFinalizer(z
, func(*Z
) {})
135 func BenchmarkFinalizer(b
*testing
.B
) {
137 b
.RunParallel(func(pb
*testing
.PB
) {
139 for i
:= 0; i
< Batch
; i
++ {
143 for i
:= 0; i
< Batch
; i
++ {
144 runtime
.SetFinalizer(data
[i
], fin
)
146 for i
:= 0; i
< Batch
; i
++ {
147 runtime
.SetFinalizer(data
[i
], nil)
153 func BenchmarkFinalizerRun(b
*testing
.B
) {
154 b
.RunParallel(func(pb
*testing
.PB
) {
157 runtime
.SetFinalizer(v
, fin
)
162 // One chunk must be exactly one sizeclass in size.
163 // It should be a sizeclass not used much by others, so we
164 // have a greater chance of finding adjacent ones.
165 // size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
168 type objtype
[objsize
]byte
170 func adjChunks() (*objtype
, *objtype
) {
175 for _
, d
:= range s
{
176 if uintptr(unsafe
.Pointer(c
))+unsafe
.Sizeof(*c
) == uintptr(unsafe
.Pointer(d
)) {
179 if uintptr(unsafe
.Pointer(d
))+unsafe
.Sizeof(*c
) == uintptr(unsafe
.Pointer(c
)) {
187 // Make sure an empty slice on the stack doesn't pin the next object in memory.
188 func TestEmptySlice(t
*testing
.T
) {
189 if runtime
.Compiler
== "gccgo" {
190 t
.Skip("skipping for gccgo")
194 // the pointer inside xs points to y.
195 xs
:= x
[objsize
:] // change objsize to objsize-1 and the test passes
197 fin
:= make(chan bool, 1)
198 runtime
.SetFinalizer(y
, func(z
*objtype
) { fin
<- true })
202 case <-time
.After(4 * time
.Second
):
203 t
.Errorf("finalizer of next object in memory didn't run")
205 xsglobal
= xs
// keep empty slice alive until here
210 func adjStringChunk() (string, *objtype
) {
211 b
:= make([]byte, objsize
)
215 p
:= *(*uintptr)(unsafe
.Pointer(&s
))
216 q
:= uintptr(unsafe
.Pointer(t
))
223 // Make sure an empty string on the stack doesn't pin the next object in memory.
224 func TestEmptyString(t
*testing
.T
) {
225 if runtime
.Compiler
== "gccgo" {
226 t
.Skip("skipping for gccgo")
229 x
, y
:= adjStringChunk()
231 ss
:= x
[objsize
:] // change objsize to objsize-1 and the test passes
232 fin
:= make(chan bool, 1)
233 // set finalizer on string contents of y
234 runtime
.SetFinalizer(y
, func(z
*objtype
) { fin
<- true })
238 case <-time
.After(4 * time
.Second
):
239 t
.Errorf("finalizer of next string in memory didn't run")
241 ssglobal
= ss
// keep 0-length string live until here
246 // Test for issue 7656.
247 func TestFinalizerOnGlobal(t
*testing
.T
) {
248 runtime
.SetFinalizer(Foo1
, func(p
*Object1
) {})
249 runtime
.SetFinalizer(Foo2
, func(p
*Object2
) {})
250 runtime
.SetFinalizer(Foo1
, nil)
251 runtime
.SetFinalizer(Foo2
, nil)
254 type Object1
struct {
258 type Object2
struct {
267 func TestDeferKeepAlive(t
*testing
.T
) {
274 type T
*int // needs to be a pointer base type to avoid tinyalloc and its never-finalized behavior.
277 runtime
.SetFinalizer(x
, func(x
*T
) {
280 defer runtime
.KeepAlive(x
)
282 time
.Sleep(time
.Second
)
284 t
.Errorf("finalizer ran prematurely")