go `cmd/compile: 避免堆栈对象的可避免构造`

yzxexxkh  于 4个月前  发布在  Go
关注(0)|答案(7)|浏览(48)

将以下文本内容编译为-live程序,显示x被转换为栈对象:

package p

var m map[int16]bool

func f() {
        var x struct { p *int; i int16 }
        x.i = g()
        m[x.i] = true
        h()
        j(x.i)
}

func g() int16
func h()
func j(int16)

这是因为赋值m[x.i] = true通过引用传递了x.i,导致x被标记为addrtaken。
请注意,用tmp := x.i; m[tmp] = true替换逻辑上等价的程序不会为x创建栈对象。

vd2z7a6w

vd2z7a6w1#

稍微更现实的测试用例。x 这里也不需要栈对象:

package p

var m map[interface{}]bool

func f() {
	x := g()
	m[x] = true
	h()
}

func g() interface{}
func h()

(编辑:实际上,它是 x 的自动临时副本,而不是 x 本身。但我的主要观点是,f 根本不需要栈对象,因为我们静态地知道那里所有变量的生命周期。)

8dtrkrch

8dtrkrch2#

https://golang.org/cl/284412提到了这个问题:[dev.regabi] cmd/compile: convert OPANIC argument to interface{} during typecheck

polhcujo

polhcujo3#

问题在于,在遍历过程中,我们将 m[k] = v 重写为大致的 *mapassign(m, &k) = v。当我们为 &k 创建节点时,它将 k 标记为 addrtaken。通常情况下,被标记为 addrtaken 的变量需要栈对象,因为我们无法跟踪指针的生命周期。
但是,当我们获取一个变量的地址并将其传递给运行时函数(如 mapassign)时,我们通常知道该变量将在运行时函数返回之前保持活动状态。在这种情况下,我们不需要栈对象的完全通用性;相反,只要我们在调用之后添加 VarLive 操作(或者可能通过使用 CallExpr.KeepAlive),那么我们就可以让活跃性分析和栈Map负责保持变量的活动状态。
这可能需要将 Addrtaken 分为两个单独的标志:一个表示变量“需要可寻址”,另一个表示“变量需要栈对象来跟踪其活动状态”。我们将为用户获取地址的变量设置这两个标志。在编译器的某些后期阶段中,至少在某些情况下,我们可能只需要设置“需要可寻址”标志。

9njqaruj

9njqaruj4#

https://golang.org/cl/321711提到了这个问题:cmd/compile: add new flag to track whether variables need stack objects

83qze16e

83qze16e5#

https://golang.org/cl/321712提到了这个问题:cmd/compile: mark OVARLIVE variables not require stack objects

y0u0uwnf

y0u0uwnf6#

https://golang.org/cl/321714提到了这个问题:cmd/compile: do not mark stack object for map key passed to runtime function

xxe27gdn

xxe27gdn7#

https://golang.org/cl/321713提到了这个问题:cmd/compile: refactor walkIndexMap

相关问题