“泛型会生成多份代码”具体是什么样?每份有什么不同?什么情况下会被合并?体积到底涨多少?这篇让 rustc 列出单态化实例,读汇编,再量目标文件大小。
MONO_ITEM fn largest::<char> @@ u126a.2d40a2df0f3cf73d-cgu.0[External] MONO_ITEM fn largest::<f64> @@ u126a.2d40a2df0f3cf73d-cgu.0[External] MONO_ITEM fn largest::<i32> @@ u126a.2d40a2df0f3cf73d-cgu.0[External] MONO_ITEM fn largest::<u8> @@ u126a.2d40a2df0f3cf73d-cgu.0[External] MONO_ITEM fn std::cmp::impls::<impl std::cmp::PartialOrd for char>::gt @@ u126a.2d40a2df0f3cf73d-cgu.0[Internal] MONO_ITEM fn std::cmp::impls::<impl std::cmp::PartialOrd for f64>::gt @@ u126a.2d40a2df0f3cf73d-cgu.0[Internal] MONO_ITEM fn std::cmp::impls::<impl std::cmp::PartialOrd for i32>::gt @@ u126a.2d40a2df0f3cf73d-cgu.0[Internal] MONO_ITEM fn std::cmp::impls::<impl std::cmp::PartialOrd for u8>::gt @@ u126a.2d40a2df0f3cf73d-cgu.0[Internal] MONO_ITEM fn use_all @@ u126a.2d40a2df0f3cf73d-cgu.0[External] 共 9 个单态化实例:largest 被实例化了 4 次(i32、f64、u8、char 各一份)
单态化的基础见泛型单态化;输出使用 RUSTC_BOOTSTRAP=1 -Z print-mono-items。
largest::<f64>(3 条指令):fcmp d0, d1 ; fcsel d0, d0, d1, gt ; ret largest::<i32>(3 条指令):cmp w0, w1 ; csel w0, w0, w1, gt ; ret largest::<u32>(3 条指令):cmp w0, w1 ; csel w0, w0, w1, hi ; ret 汇编里 largest 的符号:3 个(i32、f64、u32 各一份;u32 与 i32 比较指令不同,所以没有被合并)
汇编里别名(_x = _y):[('__RINvCs5c6pjRSpYZC_5u126c8add_pairmEB2_', '__RINvCs5c6pjRSpYZC_5u126c8add_pairlEB2_'), ('_add_u32', '_add_i32')]
实际定义的函数标签:['__RINvCs5c6pjRSpYZC_5u126c8add_pairfEB2_', '__RINvCs5c6pjRSpYZC_5u126c8add_pairlEB2_', '_add_f32', '_add_i32']函数合并是 LLVM 的优化,在 -O 下发生。
实例数 泛型版 .o 字节 &dyn 版 .o 字节
1 1,552 2,032
4 3,768 4,104
16 11,488 11,208静态与动态分发的耗时对比见静态分发与动态分发性能对比。