Go版本
Go 1.22
你做了什么?
return make([]struct{}, 123)
编译成调用 runtime.makeslice
:
LEAQ type:struct {}(SB), AX
MOVL $123, BX
MOVQ BX, CX
PCDATA $1, $0
NOP
CALL runtime.makeslice(SB)
MOVL $123, BX
MOVQ BX, CX
ADDQ $24, SP
POPQ BP
RET
我们在调用 https://pkg.go.dev/tailscale.com/types/views#Slice.LenIter (早于Go 1.22的range-over-int)时看到了这个(虽然很小,但非零):
// LenIter returns a slice the same length as the v.Len().
// The caller can then range over it to get the valid indexes.
// It does not allocate.
func (v Slice[T]) LenIter() []struct{} { return make([]struct{}, len(v.ж)) }
我意识到当类型宽度为零时,编译器可以省略这些 makeslice
调用(因为没有实际分配)。
当切片长度为零时,编译器已经这样做了:
// Recognise make([]T, 0) and replace it with a pointer to the zerobase
(StaticLECall {callAux} _ (Const(64|32) [0]) (Const(64|32) [0]) mem)
&& isSameCall(callAux, "runtime.makeslice")
=> (MakeResult (Addr <v.Type.FieldType(0)> {ir.Syms.Zerobase} (SB)) mem)
/cc @golang/compiler @twitchyliquid64@maisem
8条答案
按热度按时间dced5bon1#
我为零大小的切片添加了这个精确的优化,但我没有为零大小的类型添加它,因为我无法弄清楚如何在SSA传递中恢复编译类型指针的编译器
*types.Type
,而且这不是我想优化的内容,所以我从未调查过它。经过5分钟的搜索,当时我们失去了编译类型指针在genssa之后的类型信息,与前端对象进行交谈并不简单。
y4ekin9u2#
我们可以在
genssa
中进行这种优化,因为我们拥有所有所需的类型信息,但这很棘手,因为我们不能依赖prove
来正确证明索引是否在范围内。因为这会导致恐慌:在
genssa
期间,我们可以检查参数是否为字面量或常量,但其他任何事情都非常困难。回到你的例子:
这不会在
genssa
中被优化,就像之前一样,在prove
之前,我们不知道len(v.ж)
可能是什么。实际上没关系,len
不能返回无效长度(除了*unsafe
代码有误之外,但如果不正确使用unsafe
导致错误,那也没关系)。我甚至不确定
prove
是否能正确处理这个问题,因为它在一些边缘情况下与len
和makeslice
失败。我认为这应该在一个第三方的linter中处理,该linter找到所有的
make([]zeroSizedType, n)
调用范围,并恳请更新代码以使用int的范围遍历,git grep -F "make([]struct{}, "
应该已经让你走了95%的路程。dy1byipe3#
关于SSA规则,我想到了这个:
但我必须承认,我对这方面缺乏适当的理解,如果在优化过程中的早期阶段可能还有更好的方法来实现相同的效果。
s5a0g9ez4#
@mauri870 这个不应该在长度和容量超出范围时恐慌。
检查字符串lsym是一个有趣的想法,但它非常花哨。
对于像这样的东西不起作用:
尽管那并不那么糟糕。
6jjcrrmo5#
我同意,我的方法非常天真。可能有很多问题,如果它能以某种方式作为起点,我会很高兴。感谢关注这个问题。
0h4hbjxa6#
我将在
internal/walk
中制作一个补丁,该补丁将处理字面量、常量和len
/cap
调用作为make
的参数,如果编译器团队认为这是合适的(cc @randall77)。但是,我认为消费者应该重写他们的代码,使用int范围进行操作。kupeojn67#
是的,没问题。
我们可以为所有的
make
调用生成负测试,针对make
参数进行测试,如果满足条件则调用runtime.panicmakeslicelen
。不确定这样做是否值得。bxgwgixi8#
我认为我们应该内联热代码路径而不是冷路径。