github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/go/runtime/mfinal_test.go (about)

     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.
     4  
     5  package runtime_test
     6  
     7  import (
     8  	"runtime"
     9  	"testing"
    10  	"time"
    11  	"unsafe"
    12  )
    13  
    14  type Tintptr *int // assignable to *int
    15  type Tint int     // *Tint implements Tinter, interface{}
    16  
    17  func (t *Tint) m() {}
    18  
    19  type Tinter interface {
    20  	m()
    21  }
    22  
    23  func TestFinalizerType(t *testing.T) {
    24  	if runtime.GOARCH != "amd64" {
    25  		t.Skipf("Skipping on non-amd64 machine")
    26  	}
    27  	if runtime.Compiler == "gccgo" {
    28  		t.Skip("skipping for gccgo")
    29  	}
    30  
    31  	ch := make(chan bool, 10)
    32  	finalize := func(x *int) {
    33  		if *x != 97531 {
    34  			t.Errorf("finalizer %d, want %d", *x, 97531)
    35  		}
    36  		ch <- true
    37  	}
    38  
    39  	var finalizerTests = []struct {
    40  		convert   func(*int) interface{}
    41  		finalizer interface{}
    42  	}{
    43  		{func(x *int) interface{} { return x }, func(v *int) { finalize(v) }},
    44  		{func(x *int) interface{} { return Tintptr(x) }, func(v Tintptr) { finalize(v) }},
    45  		{func(x *int) interface{} { return Tintptr(x) }, func(v *int) { finalize(v) }},
    46  		{func(x *int) interface{} { return (*Tint)(x) }, func(v *Tint) { finalize((*int)(v)) }},
    47  		{func(x *int) interface{} { return (*Tint)(x) }, func(v Tinter) { finalize((*int)(v.(*Tint))) }},
    48  	}
    49  
    50  	for i, tt := range finalizerTests {
    51  		done := make(chan bool, 1)
    52  		go func() {
    53  			// allocate struct with pointer to avoid hitting tinyalloc.
    54  			// Otherwise we can't be sure when the allocation will
    55  			// be freed.
    56  			type T struct {
    57  				v int
    58  				p unsafe.Pointer
    59  			}
    60  			v := &new(T).v
    61  			*v = 97531
    62  			runtime.SetFinalizer(tt.convert(v), tt.finalizer)
    63  			v = nil
    64  			done <- true
    65  		}()
    66  		<-done
    67  		runtime.GC()
    68  		runtime.GC()
    69  		select {
    70  		case <-ch:
    71  		case <-time.After(time.Second * 4):
    72  			t.Errorf("#%d: finalizer for type %T didn't run", i, tt.finalizer)
    73  		}
    74  	}
    75  }
    76  
    77  type bigValue struct {
    78  	fill uint64
    79  	it   bool
    80  	up   string
    81  }
    82  
    83  func TestFinalizerInterfaceBig(t *testing.T) {
    84  	if runtime.GOARCH != "amd64" {
    85  		t.Skipf("Skipping on non-amd64 machine")
    86  	}
    87  	if runtime.Compiler == "gccgo" {
    88  		t.Skip("skipping for gccgo")
    89  	}
    90  	ch := make(chan bool)
    91  	done := make(chan bool, 1)
    92  	go func() {
    93  		v := &bigValue{0xDEADBEEFDEADBEEF, true, "It matters not how strait the gate"}
    94  		old := *v
    95  		runtime.SetFinalizer(v, func(v interface{}) {
    96  			i, ok := v.(*bigValue)
    97  			if !ok {
    98  				t.Errorf("finalizer called with type %T, want *bigValue", v)
    99  			}
   100  			if *i != old {
   101  				t.Errorf("finalizer called with %+v, want %+v", *i, old)
   102  			}
   103  			close(ch)
   104  		})
   105  		v = nil
   106  		done <- true
   107  	}()
   108  	<-done
   109  	runtime.GC()
   110  	select {
   111  	case <-ch:
   112  	case <-time.After(4 * time.Second):
   113  		t.Errorf("finalizer for type *bigValue didn't run")
   114  	}
   115  }
   116  
   117  func fin(v *int) {
   118  }
   119  
   120  // Verify we don't crash at least. golang.org/issue/6857
   121  func TestFinalizerZeroSizedStruct(t *testing.T) {
   122  	type Z struct{}
   123  	z := new(Z)
   124  	runtime.SetFinalizer(z, func(*Z) {})
   125  }
   126  
   127  func BenchmarkFinalizer(b *testing.B) {
   128  	const Batch = 1000
   129  	b.RunParallel(func(pb *testing.PB) {
   130  		var data [Batch]*int
   131  		for i := 0; i < Batch; i++ {
   132  			data[i] = new(int)
   133  		}
   134  		for pb.Next() {
   135  			for i := 0; i < Batch; i++ {
   136  				runtime.SetFinalizer(data[i], fin)
   137  			}
   138  			for i := 0; i < Batch; i++ {
   139  				runtime.SetFinalizer(data[i], nil)
   140  			}
   141  		}
   142  	})
   143  }
   144  
   145  func BenchmarkFinalizerRun(b *testing.B) {
   146  	b.RunParallel(func(pb *testing.PB) {
   147  		for pb.Next() {
   148  			v := new(int)
   149  			runtime.SetFinalizer(v, fin)
   150  		}
   151  	})
   152  }
   153  
   154  // One chunk must be exactly one sizeclass in size.
   155  // It should be a sizeclass not used much by others, so we
   156  // have a greater chance of finding adjacent ones.
   157  // size class 19: 320 byte objects, 25 per page, 1 page alloc at a time
   158  const objsize = 320
   159  
   160  type objtype [objsize]byte
   161  
   162  func adjChunks() (*objtype, *objtype) {
   163  	var s []*objtype
   164  
   165  	for {
   166  		c := new(objtype)
   167  		for _, d := range s {
   168  			if uintptr(unsafe.Pointer(c))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(d)) {
   169  				return c, d
   170  			}
   171  			if uintptr(unsafe.Pointer(d))+unsafe.Sizeof(*c) == uintptr(unsafe.Pointer(c)) {
   172  				return d, c
   173  			}
   174  		}
   175  		s = append(s, c)
   176  	}
   177  }
   178  
   179  // Make sure an empty slice on the stack doesn't pin the next object in memory.
   180  func TestEmptySlice(t *testing.T) {
   181  	if runtime.Compiler == "gccgo" {
   182  		t.Skip("skipping for gccgo")
   183  	}
   184  	x, y := adjChunks()
   185  
   186  	// the pointer inside xs points to y.
   187  	xs := x[objsize:] // change objsize to objsize-1 and the test passes
   188  
   189  	fin := make(chan bool, 1)
   190  	runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
   191  	runtime.GC()
   192  	select {
   193  	case <-fin:
   194  	case <-time.After(4 * time.Second):
   195  		t.Errorf("finalizer of next object in memory didn't run")
   196  	}
   197  	xsglobal = xs // keep empty slice alive until here
   198  }
   199  
   200  var xsglobal []byte
   201  
   202  func adjStringChunk() (string, *objtype) {
   203  	b := make([]byte, objsize)
   204  	for {
   205  		s := string(b)
   206  		t := new(objtype)
   207  		p := *(*uintptr)(unsafe.Pointer(&s))
   208  		q := uintptr(unsafe.Pointer(t))
   209  		if p+objsize == q {
   210  			return s, t
   211  		}
   212  	}
   213  }
   214  
   215  // Make sure an empty string on the stack doesn't pin the next object in memory.
   216  func TestEmptyString(t *testing.T) {
   217  	if runtime.Compiler == "gccgo" {
   218  		t.Skip("skipping for gccgo")
   219  	}
   220  
   221  	x, y := adjStringChunk()
   222  
   223  	ss := x[objsize:] // change objsize to objsize-1 and the test passes
   224  	fin := make(chan bool, 1)
   225  	// set finalizer on string contents of y
   226  	runtime.SetFinalizer(y, func(z *objtype) { fin <- true })
   227  	runtime.GC()
   228  	select {
   229  	case <-fin:
   230  	case <-time.After(4 * time.Second):
   231  		t.Errorf("finalizer of next string in memory didn't run")
   232  	}
   233  	ssglobal = ss // keep 0-length string live until here
   234  }
   235  
   236  var ssglobal string
   237  
   238  // Test for issue 7656.
   239  func TestFinalizerOnGlobal(t *testing.T) {
   240  	runtime.SetFinalizer(Foo1, func(p *Object1) {})
   241  	runtime.SetFinalizer(Foo2, func(p *Object2) {})
   242  	runtime.SetFinalizer(Foo1, nil)
   243  	runtime.SetFinalizer(Foo2, nil)
   244  }
   245  
   246  type Object1 struct {
   247  	Something []byte
   248  }
   249  
   250  type Object2 struct {
   251  	Something byte
   252  }
   253  
   254  var (
   255  	Foo2 = &Object2{}
   256  	Foo1 = &Object1{}
   257  )