1// run
2
3// Copyright 2018 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// This test makes sure that ambiguously live arguments work correctly.
8
9package main
10
11import (
12	"runtime"
13)
14
15type HeapObj [8]int64
16
17type StkObj struct {
18	h *HeapObj
19}
20
21var n int
22var c int = -1
23
24func gc() {
25	// encourage heap object to be collected, and have its finalizer run.
26	runtime.GC()
27	runtime.GC()
28	runtime.GC()
29	n++
30}
31
32var null StkObj
33
34var sink *HeapObj
35
36//go:noinline
37func use(p *StkObj) {
38}
39
40//go:noinline
41func f(s StkObj, b bool) {
42	var p *StkObj
43	if b {
44		p = &s
45	} else {
46		p = &null
47	}
48	// use is required here to prevent the conditional
49	// code above from being executed after the first gc() call.
50	use(p)
51	// If b==false, h should be collected here.
52	gc() // 0
53	sink = p.h
54	gc() // 1
55	sink = nil
56	// If b==true, h should be collected here.
57	gc() // 2
58}
59
60func fTrue() {
61	var s StkObj
62	s.h = new(HeapObj)
63	c = -1
64	n = 0
65	runtime.SetFinalizer(s.h, func(h *HeapObj) {
66		// Remember at what phase the heap object was collected.
67		c = n
68	})
69	f(s, true)
70	if c != 2 {
71		panic("bad liveness")
72	}
73}
74
75func fFalse() {
76	var s StkObj
77	s.h = new(HeapObj)
78	c = -1
79	n = 0
80	runtime.SetFinalizer(s.h, func(h *HeapObj) {
81		// Remember at what phase the heap object was collected.
82		c = n
83	})
84	f(s, false)
85	if c != 0 {
86		panic("bad liveness")
87	}
88}
89
90func main() {
91	fTrue()
92	fFalse()
93}
94