mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile,runtime: remove ambiguously live logic
The previous CL introduced stack objects. This CL removes the old ambiguously live liveness analysis. After this CL we're relying on stack objects exclusively. Update a bunch of liveness tests to reflect the new world. Fixes #22350 Change-Id: I739b26e015882231011ce6bc1a7f426049e59f31 Reviewed-on: https://go-review.googlesource.com/c/134156 Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
cbafcc55e8
commit
9a8372f8bd
16 changed files with 375 additions and 334 deletions
|
|
@ -15,10 +15,10 @@ type T struct {
|
|||
}
|
||||
|
||||
func f(a T) { // ERROR "live at entry to f: a"
|
||||
var e interface{}
|
||||
func() { // ERROR "live at entry to f.func1: a &e"
|
||||
e = a.s // ERROR "live at call to convT2Estring: a &e"
|
||||
}() // ERROR "live at call to f.func1: e$"
|
||||
var e interface{} // ERROR "stack object e interface \{\}$"
|
||||
func() { // ERROR "live at entry to f.func1: a &e"
|
||||
e = a.s // ERROR "live at call to convT2Estring: &e" "stack object a T$"
|
||||
}()
|
||||
// Before the fix, both a and e were live at the previous line.
|
||||
_ = e
|
||||
}
|
||||
|
|
|
|||
175
test/live.go
175
test/live.go
|
|
@ -32,9 +32,9 @@ func printbytepointer(*byte)
|
|||
func printint(int)
|
||||
|
||||
func f1() {
|
||||
var x *int
|
||||
printpointer(&x) // ERROR "live at call to printpointer: x$"
|
||||
var x *int // ERROR "stack object x \*int$"
|
||||
printpointer(&x) // ERROR "live at call to printpointer: x$"
|
||||
printpointer(&x)
|
||||
}
|
||||
|
||||
func f2(b bool) {
|
||||
|
|
@ -42,9 +42,9 @@ func f2(b bool) {
|
|||
printint(0) // nothing live here
|
||||
return
|
||||
}
|
||||
var x *int
|
||||
printpointer(&x) // ERROR "live at call to printpointer: x$"
|
||||
var x *int // ERROR "stack object x \*int$"
|
||||
printpointer(&x) // ERROR "live at call to printpointer: x$"
|
||||
printpointer(&x)
|
||||
}
|
||||
|
||||
func f3(b1, b2 bool) {
|
||||
|
|
@ -60,15 +60,15 @@ func f3(b1, b2 bool) {
|
|||
}
|
||||
|
||||
if b2 {
|
||||
var x *int
|
||||
printpointer(&x) // ERROR "live at call to printpointer: x$"
|
||||
var x *int // ERROR "stack object x \*int$"
|
||||
printpointer(&x) // ERROR "live at call to printpointer: x$"
|
||||
printpointer(&x)
|
||||
} else {
|
||||
var y *int
|
||||
printpointer(&y) // ERROR "live at call to printpointer: y$"
|
||||
var y *int // ERROR "stack object y \*int$"
|
||||
printpointer(&y) // ERROR "live at call to printpointer: y$"
|
||||
printpointer(&y)
|
||||
}
|
||||
printint(0) // ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
|
||||
printint(0) // nothing is live here
|
||||
}
|
||||
|
||||
// The old algorithm treated x as live on all code that
|
||||
|
|
@ -83,7 +83,7 @@ func f4(b1, b2 bool) { // x not live here
|
|||
return
|
||||
}
|
||||
var z **int
|
||||
x := new(int)
|
||||
x := new(int) // ERROR "stack object x \*int$"
|
||||
*x = 42
|
||||
z = &x
|
||||
printint(**z) // ERROR "live at call to printint: x$"
|
||||
|
|
@ -99,15 +99,15 @@ func f4(b1, b2 bool) { // x not live here
|
|||
func f5(b1 bool) {
|
||||
var z **int
|
||||
if b1 {
|
||||
x := new(int)
|
||||
x := new(int) // ERROR "stack object x \*int$"
|
||||
*x = 42
|
||||
z = &x
|
||||
} else {
|
||||
y := new(int)
|
||||
y := new(int) // ERROR "stack object y \*int$"
|
||||
*y = 54
|
||||
z = &y
|
||||
}
|
||||
printint(**z) // ERROR "f5: x \(type \*int\) is ambiguously live$" "f5: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
|
||||
printint(**z) // nothing live here
|
||||
}
|
||||
|
||||
// confusion about the _ result used to cause spurious "live at entry to f6: _".
|
||||
|
|
@ -119,7 +119,7 @@ func f6() (_, y string) {
|
|||
|
||||
// confusion about addressed results used to cause "live at entry to f7: x".
|
||||
|
||||
func f7() (x string) {
|
||||
func f7() (x string) { // ERROR "stack object x string"
|
||||
_ = &x
|
||||
x = "hello"
|
||||
return
|
||||
|
|
@ -141,7 +141,7 @@ var i9 interface{}
|
|||
func f9() bool {
|
||||
g8()
|
||||
x := i9
|
||||
y := interface{}(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+ x.data$" "live at call to str: x.data$"
|
||||
y := interface{}(str()) // ERROR "live at call to convT2Estring: x.data$" "live at call to str: x.data$" "stack object .autotmp_[0-9]+ string$"
|
||||
i9 = y // make y escape so the line above has to call convT2E
|
||||
return x != y
|
||||
}
|
||||
|
|
@ -163,7 +163,7 @@ var b bool
|
|||
|
||||
// this used to have a spurious "live at entry to f11a: ~r0"
|
||||
func f11a() *int {
|
||||
select { // ERROR "live at call to selectgo: .autotmp_[0-9]+$"
|
||||
select { // ERROR "stack object .autotmp_[0-9]+ \[2\]struct"
|
||||
case <-c:
|
||||
return nil
|
||||
case <-c:
|
||||
|
|
@ -178,7 +178,7 @@ func f11b() *int {
|
|||
// get to the bottom of the function.
|
||||
// This used to have a spurious "live at call to printint: p".
|
||||
printint(1) // nothing live here!
|
||||
select { // ERROR "live at call to selectgo: .autotmp_[0-9]+$"
|
||||
select { // ERROR "stack object .autotmp_[0-9]+ \[2\]struct"
|
||||
case <-c:
|
||||
return nil
|
||||
case <-c:
|
||||
|
|
@ -198,7 +198,7 @@ func f11c() *int {
|
|||
// Unlike previous, the cases in this select fall through,
|
||||
// so we can get to the println, so p is not dead.
|
||||
printint(1) // ERROR "live at call to printint: p$"
|
||||
select { // ERROR "live at call to selectgo: .autotmp_[0-9]+ p$"
|
||||
select { // ERROR "live at call to selectgo: p$" "stack object .autotmp_[0-9]+ \[2\]struct"
|
||||
case <-c:
|
||||
case <-c:
|
||||
}
|
||||
|
|
@ -233,8 +233,8 @@ func h13(string, string) string
|
|||
// more incorrectly placed VARDEF.
|
||||
|
||||
func f14() {
|
||||
x := g14()
|
||||
printstringpointer(&x) // ERROR "live at call to printstringpointer: x$"
|
||||
x := g14() // ERROR "stack object x string$"
|
||||
printstringpointer(&x)
|
||||
}
|
||||
|
||||
func g14() string
|
||||
|
|
@ -254,10 +254,10 @@ func iface() interface{}
|
|||
|
||||
func f16() {
|
||||
if b {
|
||||
delete(mi, iface()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
|
||||
delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
|
||||
}
|
||||
delete(mi, iface()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
|
||||
delete(mi, iface()) // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
|
||||
delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
|
||||
delete(mi, iface()) // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
|
||||
}
|
||||
|
||||
var m2s map[string]*byte
|
||||
|
|
@ -300,10 +300,10 @@ func f18() {
|
|||
// temporary introduced by orderexpr.
|
||||
var z *byte
|
||||
if b {
|
||||
z = m2[g18()] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
z = m2[g18()] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
z = m2[g18()] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
z = m2[g18()] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
printbytepointer(z)
|
||||
}
|
||||
|
||||
|
|
@ -317,30 +317,30 @@ func f19() {
|
|||
var z *byte
|
||||
|
||||
if b {
|
||||
z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
|
||||
z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$"
|
||||
}
|
||||
z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
|
||||
z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
|
||||
z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$"
|
||||
z = <-ch // ERROR "stack object .autotmp_[0-9]+ \*byte$" "live at call to chanrecv1: .autotmp_[0-9]+$"
|
||||
printbytepointer(z)
|
||||
}
|
||||
|
||||
func f20() {
|
||||
// src temporary for channel send
|
||||
if b {
|
||||
ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
|
||||
ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
|
||||
}
|
||||
ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
|
||||
ch <- byteptr() // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
|
||||
ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
|
||||
ch <- byteptr() // ERROR "stack object .autotmp_[0-9]+ \*byte$"
|
||||
}
|
||||
|
||||
func f21() {
|
||||
// key temporary for mapaccess using array literal key.
|
||||
var z *byte
|
||||
if b {
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
printbytepointer(z)
|
||||
}
|
||||
|
||||
|
|
@ -349,10 +349,10 @@ func f23() {
|
|||
var z *byte
|
||||
var ok bool
|
||||
if b {
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: .autotmp_[0-9]+$"
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: .autotmp_[0-9]+$"
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: .autotmp_[0-9]+$"
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
printbytepointer(z)
|
||||
print(ok)
|
||||
}
|
||||
|
|
@ -361,10 +361,10 @@ func f24() {
|
|||
// key temporary for map access using array literal key.
|
||||
// value temporary too.
|
||||
if b {
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign: .autotmp_[0-9]+$"
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign: .autotmp_[0-9]+$"
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign: .autotmp_[0-9]+$"
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
|
||||
// defer should not cause spurious ambiguously live variables
|
||||
|
|
@ -387,10 +387,10 @@ func g25()
|
|||
|
||||
func f26(b bool) {
|
||||
if b {
|
||||
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: .autotmp_[0-9]+$"
|
||||
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
|
||||
}
|
||||
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: .autotmp_[0-9]+$"
|
||||
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: .autotmp_[0-9]+$"
|
||||
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
|
||||
print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "stack object .autotmp_[0-9]+ \[3\]interface \{\}$"
|
||||
printnl()
|
||||
}
|
||||
|
||||
|
|
@ -402,10 +402,10 @@ func print26(...interface{})
|
|||
func f27(b bool) {
|
||||
x := 0
|
||||
if b {
|
||||
call27(func() { x++ }) // ERROR "live at call to call27: .autotmp_[0-9]+$"
|
||||
call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
}
|
||||
call27(func() { x++ }) // ERROR "live at call to call27: .autotmp_[0-9]+$"
|
||||
call27(func() { x++ }) // ERROR "live at call to call27: .autotmp_[0-9]+$"
|
||||
call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
printnl()
|
||||
}
|
||||
|
||||
|
|
@ -414,11 +414,11 @@ func f27(b bool) {
|
|||
func f27defer(b bool) {
|
||||
x := 0
|
||||
if b {
|
||||
defer call27(func() { x++ }) // ERROR "live at call to deferproc: .autotmp_[0-9]+$" "live at call to deferreturn: .autotmp_[0-9]+$"
|
||||
defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
}
|
||||
defer call27(func() { x++ }) // ERROR "f27defer: .autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to deferreturn: .autotmp_[0-9]+ .autotmp_[0-9]+$"
|
||||
printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ .autotmp_[0-9]+$"
|
||||
} // ERROR "live at call to deferreturn: .autotmp_[0-9]+ .autotmp_[0-9]+$"
|
||||
defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
printnl()
|
||||
}
|
||||
|
||||
// and newproc (go) escapes to the heap
|
||||
|
||||
|
|
@ -440,24 +440,24 @@ var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
|
|||
|
||||
func f28(b bool) {
|
||||
if b {
|
||||
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: .autotmp_[0-9]+$" "live at call to printstring: .autotmp_[0-9]+$"
|
||||
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
|
||||
}
|
||||
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: .autotmp_[0-9]+$" "live at call to printstring: .autotmp_[0-9]+$"
|
||||
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: .autotmp_[0-9]+$" "live at call to printstring: .autotmp_[0-9]+$"
|
||||
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
|
||||
printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "stack object .autotmp_[0-9]+ \[10\]string$"
|
||||
}
|
||||
|
||||
// map iterator should die on end of range loop
|
||||
|
||||
func f29(b bool) {
|
||||
if b {
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ map.iter\[string\]int$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
|
|
@ -473,20 +473,19 @@ type pstruct struct {
|
|||
}
|
||||
|
||||
func f30(b bool) {
|
||||
// two live temps during printintpointer(p):
|
||||
// in the copy of p.intp and
|
||||
// live temp during printintpointer(p):
|
||||
// the internal iterator pointer if a pointer to pstruct in pstructarr
|
||||
// can not be easily computed by strength reduction.
|
||||
if b {
|
||||
for _, p := range pstructarr {
|
||||
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+ .autotmp_[0-9]+$"
|
||||
for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
|
||||
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
for _, p := range pstructarr {
|
||||
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+ .autotmp_[0-9]+$"
|
||||
for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
|
||||
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
|
||||
}
|
||||
for _, p := range pstructarr {
|
||||
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+ .autotmp_[0-9]+$"
|
||||
for _, p := range pstructarr { // ERROR "stack object .autotmp_[0-9]+ \[10\]pstruct$"
|
||||
printintpointer(p.intp) // ERROR "live at call to printintpointer: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -494,13 +493,13 @@ func f30(b bool) {
|
|||
|
||||
func f31(b1, b2, b3 bool) {
|
||||
if b1 {
|
||||
g31(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+$" "live at call to g31: .autotmp_[0-9]+$"
|
||||
g31(str()) // ERROR "stack object .autotmp_[0-9]+ string$"
|
||||
}
|
||||
if b2 {
|
||||
h31(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to h31: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
|
||||
h31(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ string$"
|
||||
}
|
||||
if b3 {
|
||||
panic(str()) // ERROR "live at call to convT2Estring: .autotmp_[0-9]+$" "live at call to gopanic: .autotmp_[0-9]+$"
|
||||
panic(str()) // ERROR "stack object .autotmp_[0-9]+ string$"
|
||||
}
|
||||
print(b3)
|
||||
}
|
||||
|
|
@ -520,10 +519,10 @@ var t32 T32
|
|||
|
||||
func f32(b bool) {
|
||||
if b {
|
||||
call32(t32.Inc) // ERROR "live at call to call32: .autotmp_[0-9]+$"
|
||||
call32(t32.Inc) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
}
|
||||
call32(t32.Inc) // ERROR "live at call to call32: .autotmp_[0-9]+$"
|
||||
call32(t32.Inc) // ERROR "live at call to call32: .autotmp_[0-9]+$"
|
||||
call32(t32.Inc) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
call32(t32.Inc) // ERROR "stack object .autotmp_[0-9]+ struct \{"
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
|
|
@ -535,7 +534,7 @@ func call32(func())
|
|||
var m33 map[interface{}]int
|
||||
|
||||
func f33() {
|
||||
if m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
if m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
|
||||
printnl()
|
||||
return
|
||||
} else {
|
||||
|
|
@ -545,7 +544,7 @@ func f33() {
|
|||
}
|
||||
|
||||
func f34() {
|
||||
if m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
|
||||
if m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}$"
|
||||
printnl()
|
||||
return
|
||||
}
|
||||
|
|
@ -553,7 +552,8 @@ func f34() {
|
|||
}
|
||||
|
||||
func f35() {
|
||||
if m33[byteptr()] == 0 && m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" "f35: .autotmp_[0-9]+ \(type interface \{\}\) is ambiguously live$"
|
||||
if m33[byteptr()] == 0 && // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
printnl()
|
||||
return
|
||||
}
|
||||
|
|
@ -561,7 +561,8 @@ func f35() {
|
|||
}
|
||||
|
||||
func f36() {
|
||||
if m33[byteptr()] == 0 || m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" "f36: .autotmp_[0-9]+ \(type interface \{\}\) is ambiguously live$"
|
||||
if m33[byteptr()] == 0 || // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
printnl()
|
||||
return
|
||||
}
|
||||
|
|
@ -569,7 +570,9 @@ func f36() {
|
|||
}
|
||||
|
||||
func f37() {
|
||||
if (m33[byteptr()] == 0 || m33[byteptr()] == 0) && m33[byteptr()] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$" "f37: .autotmp_[0-9]+ \(type interface \{\}\) is ambiguously live$"
|
||||
if (m33[byteptr()] == 0 || // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
m33[byteptr()] == 0) && // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
m33[byteptr()] == 0 { // ERROR "stack object .autotmp_[0-9]+ interface \{\}"
|
||||
printnl()
|
||||
return
|
||||
}
|
||||
|
|
@ -589,14 +592,14 @@ func f38(b bool) {
|
|||
// we care that the println lines have no live variables
|
||||
// and therefore no output.
|
||||
if b {
|
||||
select { // ERROR "live at call to selectgo:( .autotmp_[0-9]+)+$"
|
||||
select { // ERROR "live at call to selectgo:( .autotmp_[0-9]+)+$" "stack object .autotmp_[0-9]+ \[4\]struct \{"
|
||||
case <-fc38():
|
||||
printnl()
|
||||
case fc38() <- *fi38(1): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$"
|
||||
case fc38() <- *fi38(1): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "stack object .autotmp_[0-9]+ string$"
|
||||
printnl()
|
||||
case *fi38(2) = <-fc38(): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$"
|
||||
case *fi38(2) = <-fc38(): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "stack object .autotmp_[0-9]+ string$"
|
||||
printnl()
|
||||
case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38:( .autotmp_[0-9]+)+$" "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$"
|
||||
case *fi38(3), *fb38() = <-fc38(): // ERROR "stack object .autotmp_[0-9]+ string$" "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$"
|
||||
printnl()
|
||||
}
|
||||
printnl()
|
||||
|
|
@ -655,15 +658,17 @@ func bad40() {
|
|||
}
|
||||
|
||||
func good40() {
|
||||
ret := T40{}
|
||||
ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+ ret$"
|
||||
ret := T40{} // ERROR "stack object ret T40$"
|
||||
ret.m = make(map[int]int) // ERROR "live at call to fastrand: .autotmp_[0-9]+ ret$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
|
||||
t := &ret
|
||||
printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
|
||||
useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
|
||||
printnl() // ERROR "live at call to printnl: ret$"
|
||||
// Note: ret is live at the printnl because the compiler moves &ret
|
||||
// from before the printnl to after.
|
||||
useT40(t)
|
||||
}
|
||||
|
||||
func ddd1(x, y *int) { // ERROR "live at entry to ddd1: x y$"
|
||||
ddd2(x, y) // ERROR "live at call to ddd2: .autotmp_[0-9]+$"
|
||||
ddd2(x, y) // ERROR "stack object .autotmp_[0-9]+ \[2\]\*int$"
|
||||
printnl()
|
||||
// Note: no .?autotmp live at printnl. See issue 16996.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
package main
|
||||
|
||||
// issue 8142: lost 'addrtaken' bit on inlined variables.
|
||||
// no inlining in this test, so just checking that non-inlined works.
|
||||
|
||||
func printnl()
|
||||
|
||||
|
|
@ -28,15 +27,15 @@ func newT40() *T40 {
|
|||
}
|
||||
|
||||
func bad40() {
|
||||
t := newT40() // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
|
||||
printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
|
||||
useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
|
||||
t := newT40() // ERROR "live at call to makemap: ret$" "stack object ret T40$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
|
||||
printnl() // ERROR "live at call to printnl: ret$"
|
||||
useT40(t)
|
||||
}
|
||||
|
||||
func good40() {
|
||||
ret := T40{}
|
||||
ret.m = make(map[int]int, 42) // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
|
||||
ret := T40{} // ERROR "stack object ret T40$"
|
||||
ret.m = make(map[int]int, 42) // ERROR "live at call to makemap: ret$" "stack object .autotmp_[0-9]+ map.hdr\[int\]int$"
|
||||
t := &ret
|
||||
printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
|
||||
useT40(t) // ERROR "live at call to useT40: .autotmp_[0-9]+ ret$"
|
||||
printnl() // ERROR "live at call to printnl: ret$"
|
||||
useT40(t)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,22 +19,22 @@ func f(uintptr) // ERROR "f assuming arg#1 is unsafe uintptr"
|
|||
|
||||
func g() {
|
||||
var t int
|
||||
f(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to f: .?autotmp" "g &t does not escape"
|
||||
f(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to f: .?autotmp" "g &t does not escape" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
}
|
||||
|
||||
func h() {
|
||||
var v int
|
||||
syscall.Syscall(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to Syscall: .?autotmp" "h &v does not escape"
|
||||
syscall.Syscall(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to Syscall: .?autotmp" "h &v does not escape" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
}
|
||||
|
||||
func i() {
|
||||
var t int
|
||||
p := unsafe.Pointer(&t) // ERROR "i &t does not escape"
|
||||
f(uintptr(p)) // ERROR "live at call to f: .?autotmp"
|
||||
f(uintptr(p)) // ERROR "live at call to f: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
}
|
||||
|
||||
func j() {
|
||||
var v int
|
||||
p := unsafe.Pointer(&v) // ERROR "j &v does not escape"
|
||||
syscall.Syscall(0, 1, uintptr(p), 2) // ERROR "live at call to Syscall: .?autotmp"
|
||||
syscall.Syscall(0, 1, uintptr(p), 2) // ERROR "live at call to Syscall: .?autotmp" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
}
|
||||
|
|
|
|||
57
test/stackobj.go
Normal file
57
test/stackobj.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// run
|
||||
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type HeapObj [8]int64
|
||||
|
||||
type StkObj struct {
|
||||
h *HeapObj
|
||||
}
|
||||
|
||||
var n int
|
||||
var c int = -1
|
||||
|
||||
func gc() {
|
||||
// encourage heap object to be collected, and have its finalizer run.
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
n++
|
||||
}
|
||||
|
||||
func main() {
|
||||
f()
|
||||
gc() // prior to stack objects, heap object is not collected until here
|
||||
if c < 0 {
|
||||
panic("heap object never collected")
|
||||
}
|
||||
if c != 1 {
|
||||
panic(fmt.Sprintf("expected collection at phase 1, got phase %d", c))
|
||||
}
|
||||
}
|
||||
|
||||
func f() {
|
||||
var s StkObj
|
||||
s.h = new(HeapObj)
|
||||
runtime.SetFinalizer(s.h, func(h *HeapObj) {
|
||||
// Remember at what phase the heap object was collected.
|
||||
c = n
|
||||
})
|
||||
g(&s)
|
||||
gc()
|
||||
}
|
||||
|
||||
func g(s *StkObj) {
|
||||
gc() // heap object is still live here
|
||||
runtime.KeepAlive(s)
|
||||
gc() // heap object should be collected here
|
||||
}
|
||||
93
test/stackobj3.go
Normal file
93
test/stackobj3.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// run
|
||||
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This test makes sure that ambiguously live arguments work correctly.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
type HeapObj [8]int64
|
||||
|
||||
type StkObj struct {
|
||||
h *HeapObj
|
||||
}
|
||||
|
||||
var n int
|
||||
var c int = -1
|
||||
|
||||
func gc() {
|
||||
// encourage heap object to be collected, and have its finalizer run.
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
n++
|
||||
}
|
||||
|
||||
var null StkObj
|
||||
|
||||
var sink *HeapObj
|
||||
|
||||
//go:noinline
|
||||
func use(p *StkObj) {
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f(s StkObj, b bool) {
|
||||
var p *StkObj
|
||||
if b {
|
||||
p = &s
|
||||
} else {
|
||||
p = &null
|
||||
}
|
||||
// use is required here to prevent the conditional
|
||||
// code above from being executed after the first gc() call.
|
||||
use(p)
|
||||
// If b==false, h should be collected here.
|
||||
gc() // 0
|
||||
sink = p.h
|
||||
gc() // 1
|
||||
sink = nil
|
||||
// If b==true, h should be collected here.
|
||||
gc() // 2
|
||||
}
|
||||
|
||||
func fTrue() {
|
||||
var s StkObj
|
||||
s.h = new(HeapObj)
|
||||
c = -1
|
||||
n = 0
|
||||
runtime.SetFinalizer(s.h, func(h *HeapObj) {
|
||||
// Remember at what phase the heap object was collected.
|
||||
c = n
|
||||
})
|
||||
f(s, true)
|
||||
if c != 2 {
|
||||
panic("bad liveness")
|
||||
}
|
||||
}
|
||||
|
||||
func fFalse() {
|
||||
var s StkObj
|
||||
s.h = new(HeapObj)
|
||||
c = -1
|
||||
n = 0
|
||||
runtime.SetFinalizer(s.h, func(h *HeapObj) {
|
||||
// Remember at what phase the heap object was collected.
|
||||
c = n
|
||||
})
|
||||
f(s, false)
|
||||
if c != 0 {
|
||||
panic("bad liveness")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fTrue()
|
||||
fFalse()
|
||||
}
|
||||
|
|
@ -30,14 +30,14 @@ func F4(...uintptr) {} // ERROR "escaping ...uintptr"
|
|||
|
||||
func G() {
|
||||
var t int // ERROR "moved to heap"
|
||||
F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "&t escapes to heap"
|
||||
F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "&t escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
var t2 int // ERROR "moved to heap"
|
||||
F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "&t2 escapes to heap"
|
||||
F3(uintptr(unsafe.Pointer(&t2))) // ERROR "live at call to F3: .?autotmp" "&t2 escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
}
|
||||
|
||||
func H() {
|
||||
var v int // ERROR "moved to heap"
|
||||
F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F2: .?autotmp" "escapes to heap"
|
||||
F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F2: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
var v2 int // ERROR "moved to heap"
|
||||
F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap"
|
||||
F4(0, 1, uintptr(unsafe.Pointer(&v2)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F4: .?autotmp" "escapes to heap" "stack object .autotmp_[0-9]+ unsafe.Pointer$"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue