将以下文本内容编译为-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
创建栈对象。
7条答案
按热度按时间vd2z7a6w1#
稍微更现实的测试用例。
x
这里也不需要栈对象:(编辑:实际上,它是
x
的自动临时副本,而不是x
本身。但我的主要观点是,f
根本不需要栈对象,因为我们静态地知道那里所有变量的生命周期。)8dtrkrch2#
https://golang.org/cl/284412提到了这个问题:
[dev.regabi] cmd/compile: convert OPANIC argument to interface{} during typecheck
polhcujo3#
问题在于,在遍历过程中,我们将
m[k] = v
重写为大致的*mapassign(m, &k) = v
。当我们为&k
创建节点时,它将k
标记为 addrtaken。通常情况下,被标记为 addrtaken 的变量需要栈对象,因为我们无法跟踪指针的生命周期。但是,当我们获取一个变量的地址并将其传递给运行时函数(如 mapassign)时,我们通常知道该变量将在运行时函数返回之前保持活动状态。在这种情况下,我们不需要栈对象的完全通用性;相反,只要我们在调用之后添加 VarLive 操作(或者可能通过使用 CallExpr.KeepAlive),那么我们就可以让活跃性分析和栈Map负责保持变量的活动状态。
这可能需要将 Addrtaken 分为两个单独的标志:一个表示变量“需要可寻址”,另一个表示“变量需要栈对象来跟踪其活动状态”。我们将为用户获取地址的变量设置这两个标志。在编译器的某些后期阶段中,至少在某些情况下,我们可能只需要设置“需要可寻址”标志。
9njqaruj4#
https://golang.org/cl/321711提到了这个问题:
cmd/compile: add new flag to track whether variables need stack objects
83qze16e5#
https://golang.org/cl/321712提到了这个问题:
cmd/compile: mark OVARLIVE variables not require stack objects
y0u0uwnf6#
https://golang.org/cl/321714提到了这个问题:
cmd/compile: do not mark stack object for map key passed to runtime function
xxe27gdn7#
https://golang.org/cl/321713提到了这个问题:
cmd/compile: refactor walkIndexMap