Rebase.
[official-gcc.git] / libgo / go / runtime / mfinal_test.go
blobb47f83c3923ff5bd70d620c3ac336597048da6b1
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.
5 package runtime_test
7 import (
8 "runtime"
9 "testing"
10 "time"
11 "unsafe"
14 type Tintptr *int // assignable to *int
15 type Tint int // *Tint implements Tinter, interface{}
17 func (t *Tint) m() {}
19 type Tinter interface {
20 m()
23 func TestFinalizerType(t *testing.T) {
24 if runtime.GOARCH != "amd64" {
25 t.Skipf("Skipping on non-amd64 machine")
28 ch := make(chan bool, 10)
29 finalize := func(x *int) {
30 if *x != 97531 {
31 t.Errorf("finalizer %d, want %d", *x, 97531)
33 ch <- true
36 var finalizerTests = []struct {
37 convert func(*int) interface{}
38 finalizer interface{}
40 {func(x *int) interface{} { return x }, func(v *int) { finalize(v) }},
41 {func(x *int) interface{} { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
42 {func(x *int) interface{} { return Tintptr(x) }, func(v *int) { finalize(v) }},
43 {func(x *int) interface{} { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
44 {func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
47 for _, tt := range finalizerTests {
48 done := make(chan bool, 1)
49 go func() {
50 v := new(int)
51 *v = 97531
52 runtime.SetFinalizer(tt.convert(v), tt.finalizer)
53 v = nil
54 done <- true
55 }()
56 <-done
57 runtime.GC()
58 select {
59 case <-ch:
60 case <-time.After(time.Second * 4):
61 t.Errorf("finalizer for type %T didn't run", tt.finalizer)
66 type bigValue struct {
67 fill uint64
68 it bool
69 up string
72 func TestFinalizerInterfaceBig(t *testing.T) {
73 if runtime.GOARCH != "amd64" {
74 t.Skipf("Skipping on non-amd64 machine")
76 ch := make(chan bool)
77 done := make(chan bool, 1)
78 go func() {
79 v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
80 old := *v
81 runtime.SetFinalizer(v, func(v interface{}) {
82 i, ok := v.(*bigValue)
83 if !ok {
84 t.Errorf("finalizer called with type %T, want *bigValue", v)
86 if *i != old {
87 t.Errorf("finalizer called with %+v, want %+v", *i, old)
89 close(ch)
91 v = nil
92 done <- true
93 }()
94 <-done
95 runtime.GC()
96 select {
97 case <-ch:
98 case <-time.After(4 * time.Second):
99 t.Errorf("finalizer for type *bigValue didn't run")
103 func fin(v *int) {
106 // Verify we don't crash at least. golang.org/issue/6857
107 func TestFinalizerZeroSizedStruct(t *testing.T) {
108 type Z struct{}
109 z := new(Z)
110 runtime.SetFinalizer(z, func(*Z) {})
113 func BenchmarkFinalizer(b *testing.B) {
114 const Batch = 1000
115 b.RunParallel(func(pb *testing.PB) {
116 var data [Batch]*int
117 for i := 0; i < Batch; i++ {
118 data[i] = new(int)
120 for pb.Next() {
121 for i := 0; i < Batch; i++ {
122 runtime.SetFinalizer(data[i], fin)
124 for i := 0; i < Batch; i++ {
125 runtime.SetFinalizer(data[i], nil)
131 func BenchmarkFinalizerRun(b *testing.B) {
132 b.RunParallel(func(pb *testing.PB) {
133 for pb.Next() {
134 v := new(int)
135 runtime.SetFinalizer(v, fin)
140 // One chunk must be exactly one sizeclass in size.
141 // It should be a sizeclass not used much by others, so we
142 // have a greater chance of finding adjacent ones.
143 // size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
144 const objsize = 320
146 type objtype [objsize]byte
148 func adjChunks() (*objtype, *objtype) {
149 var s []*objtype
151 for {
152 c := new(objtype)
153 for _, d := range s {
154 if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
155 return c, d
157 if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
158 return d, c
161 s = append(s, c)
165 // Make sure an empty slice on the stack doesn't pin the next object in memory.
166 func TestEmptySlice(t *testing.T) {
167 if true { // disable until bug 7564 is fixed.
168 return
170 x, y := adjChunks()
172 // the pointer inside xs points to y.
173 xs := x[objsize:] // change objsize to objsize-1 and the test passes
175 fin := make(chan bool, 1)
176 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
177 runtime.GC()
178 select {
179 case <-fin:
180 case <-time.After(4 * time.Second):
181 t.Errorf("finalizer of next object in memory didn't run")
183 xsglobal = xs // keep empty slice alive until here
186 var xsglobal []byte
188 func adjStringChunk() (string, *objtype) {
189 b := make([]byte, objsize)
190 for {
191 s := string(b)
192 t := new(objtype)
193 p := *(*uintptr)(unsafe.Pointer(&s))
194 q := uintptr(unsafe.Pointer(t))
195 if p+objsize == q {
196 return s, t
201 // Make sure an empty string on the stack doesn't pin the next object in memory.
202 func TestEmptyString(t *testing.T) {
203 if runtime.Compiler == "gccgo" {
204 t.Skip("skipping for gccgo")
207 x, y := adjStringChunk()
209 ss := x[objsize:] // change objsize to objsize-1 and the test passes
210 fin := make(chan bool, 1)
211 // set finalizer on string contents of y
212 runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
213 runtime.GC()
214 select {
215 case <-fin:
216 case <-time.After(4 * time.Second):
217 t.Errorf("finalizer of next string in memory didn't run")
219 ssglobal = ss // keep 0-length string live until here
222 var ssglobal string
224 // Test for issue 7656.
225 func TestFinalizerOnGlobal(t *testing.T) {
226 runtime.SetFinalizer(Foo1, func(p *Object1) {})
227 runtime.SetFinalizer(Foo2, func(p *Object2) {})
228 runtime.SetFinalizer(Foo1, nil)
229 runtime.SetFinalizer(Foo2, nil)
232 type Object1 struct {
233 Something []byte
236 type Object2 struct {
237 Something byte
240 var (
241 Foo2 = &Object2{}
242 Foo1 = &Object1{}