Skip to content

Box::new copies generated Future unless call is wrapped #100932

Closed
@jkarneges

Description

@jkarneges

Sometimes boxing a generated Future causes the value to be (unnecessarily?) copied. This can be worked around by wrapping the call to Box::new.

Code:

use std::future::ready;
use std::mem;

struct Foo {}

impl Drop for Foo {
    fn drop(&mut self) {
        println!("foo");
    }
}

async fn func1() {
    let _f = Foo {};
    let mut buf = [0u8; 16_384];
    buf[0] = 42;
    ready(()).await;
    println!("{}", buf[0]);
}

fn _box_new<T>(x: T) -> Box<T> {
    Box::new(x)
}

fn take<T>(v: T) {
    println!("{}", mem::size_of_val(&v));
}

fn main() {
    take(Box::new(func1()));
    //take(_box_new(func1()));
}

Asm contains a ~16k memcpy:

$ rustc -O --edition 2021 --emit asm boxcopybug.rs && grep -B 3 memcpy boxcopybug.s
        leaq    32(%rsp), %rsi
        movl    $16386, %edx
        movq    %rax, %rdi
        callq   *memcpy@GOTPCREL(%rip)

In main, if you comment out the first line and uncomment the second, the memcpy goes away, even though the code is nearly identical. I'd expect both ways to compile down the same.

Box::pin is similarly affected.

The behavior is present in the latest stable and nightly.

rustc --version --verbose:

rustc 1.63.0 (4b91a6ea7 2022-08-08)
binary: rustc
commit-hash: 4b91a6ea7258a947e59c6522cd5898e7c0a6a88f
commit-date: 2022-08-08
host: x86_64-unknown-linux-gnu
release: 1.63.0
LLVM version: 14.0.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-layoutArea: Memory layout of typesC-bugCategory: This is a bug.I-slowIssue: Problems and improvements with respect to performance of generated code.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions