-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
derived Clone implementations for many-variant enums are unnecessarily large #47796
Comments
I was thinking about this earlier: The current Clone thing works at macro expansion time; which means that we don't know what is and isn't Copy. Except for types defined in other crates. One way to fix this would be to introduce How high priority is this for Stylo? I could take a crack at it but it will take time. I'm also unsure if the Rust folks would want such a solution (imo this can be a speed win as well). @eddyb how well do you think this can work? Where do you think this should be introduced in the pipeline? |
An alternate way of doing it is to continue generating the match, but in a later MIR pass collapse all the copy arms into a memcpy. The pass is triggered by tagging the generated impl, and runs before other MIR opts. May be fragile, but I think it should work. Needs to be post-monomorphization again but I think MIR is post-monomorphization anyway. |
Wait, I thought this was about emtpy enum variants, not And no, MIR is pre-monomorphization (it's what we run the MIR borrowck on, which limits its design). Collapsing correctly is harder than not generating the code in the first place. |
No, it's about enum variants that contain only POD. Can you point me to these shims? The reason I'm going through an intrinsic is that derive() is fundamentally an expansion step; we have to expand to something, even if it's a "fill this in later" placeholder intrinsic. Oh, also, if we do this we need to check for types where the clone impl is a copy (or is autogenerated), since clone impls for pod types can still do arbitrary things. |
I just want to give a tip for a way to get clearer ASM/LLVM IR output on the playground, with no noise from formatting or main: (playground link) |
Oh, btw this can't be done for partialeq. derive(Clone) is allowed to copy Copy things (even if Copy fields have a different Clone impl), but PartialEq doesn't work the same way. Comparing things like enums for example involves comparing specific bits (other bits may get reused). |
Also note that |
@Manishearth I'm guessing this could end up saving ~100k in libxul, which is a reasonably big fish as far as these things go - even ignoring the impact on performance, build time, and everyone else in the ecosystem. If you can put in a week or so to make this work, I think that's very much worth doing from a Firefox perspective. If you think it's measured in months, we should evaluate the tradeoffs against your other priorities. I'm not particularly informed about this stuff, but it does seem to me like it would make sense to spit out a placeholder in the derive step, and then have the compiler generate the right thing post-monomorphization once it's clear which types are Copy. As for PartialEq, could we at least get the benefits here for Copy types of the same size? @bluss - Nice trick, that will save me time. Thanks! |
Only if it has to go through the RFC process, otherwise it's a few hours / days of hacking unless you're trying to implement an after-the-fact optimization.
We already have something (used for
No, if you have any padding bytes or any non-integer leaves, you can't use |
@bholley yeah the impl work shouldn't take long. Pushing for it through the RFC process, as Eddy says, might. Post-monomorphization would be nice, but harder to achieve. Right now we directly hand off to LLVM during monomorphization so inserting more stuff there may not be great). All this means is that if you This could affect us a bit; many of our generic enums are full of Copy types (usually Au) in computed mode. But I suspect it will still be worth it. |
(Slightly off-topic for this issue: for other method like |
For generic enums, we again have a very important distinction, in whether the many-variant enums are generic over |
Some of the variants of |
Yeah this is also enums with possibly-copy types in their generics. The main one that's problematic isn't of this type, but various generic property enums are. I think assuming all generics are !Copy is a good-enough solution for most of the problem though . |
You don't get a choice if you work at the MIR level - if a bound implies |
Yeah, I mistyped and edited that, meant to say "good enough solution for most of the problem" |
There is a seemingly-working WIP at #47867 |
The derived Clone implementations in Firefox weigh 192k [1], which is a lot.
Of that 192k, 79k of that is just for PropertyDeclaration::clone. PropertyDeclaration is a very large enum, but most of the variants are simple POD types. Ideally Rust would coalesce those together, and then generate special cases for the types that need it. Unfortunately, it appears that adding a single non-POD variant causes all the cases to be enumerated separately, as seen in the testcase at [2].
From IRC:
Ideally we'd do the same for PartialEq, since PropertyDeclaration::eq weighs another 61k.
[1] nm --print-size --size-sort --radix=d libxul.so | grep "..Clone" | grep -v Cloned | cut -d " " -f 2 | awk '{s+=$1} END {print s}'
[2] https://play.rust-lang.org/?gist=0207af76d2e05acdbed913b7df96aa77&version=stable
The text was updated successfully, but these errors were encountered: