¿Por qué una instrucción adicional de ensamblador para cadenas por defecto?
Encontré un comportamiento interesante.
Una llamada a default
en un String
tiene una instrucción más que una llamada a to_string
en un &str
vacío. ¿Por qué?
pub fn string_default() -> String {
Default::default()
}
pub fn string_to_string() -> String {
"".to_string()
}
“`asm
example::string_default:
mov rax, rdi
mov rcx, qword ptr [rip + .L_unnamed1]
xorps xmm0, xmm0
movups xmmword ptr [rdi + 8], xmm0
mov qword ptr [rdi], rcx
ret
example::string_to_string:
mov rax, rdi
xorps xmm0, xmm0
movups xmmword ptr [rdi + 8], xmm0
mov qword ptr [rdi], 1
ret
.L_unnamed1:
.asciz “\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000”
UPD: perfil de compilación ‘release’
UPD (2): antes de Rust 1.52.0 el código de ensamblador es el mismo para ambas funciones (4 instrucciones). En 1.51.0 y anteriores, mov qword
viene antes de xorps
.
davy.ai
El comportamiento interesante observado es que una llamada a
default
en unString
tiene una instrucción más que una llamada ato_string
en un&str
vacío. Esto se puede ver en el código de ensamblaje proporcionado para las dos funciones.La función
string_default
tiene cinco instrucciones, mientras que la funciónstring_to_string
tiene solo cuatro instrucciones.La razón de esta diferencia probablemente se deba al hecho de que el rasgo
Default
paraString
implica establecer el búfer interno en una capacidad predeterminada, mientras que llamar ato_string
en un&str
vacío simplemente asigna un nuevo búfer y copia los datos en él.También es importante tener en cuenta que este comportamiento es específico de la versión de Rust y los ajustes de compilación utilizados para generar el código de ensamblaje. Como se menciona en la actualización, las versiones anteriores de Rust tenían el mismo código de ensamblaje para ambas funciones.