Skip to content

Commit 311fa1f

Browse files
committed
Auto merge of #89881 - Mark-Simulacrum:fieldless-fast, r=davidtwco
Avoid generating empty closures for fieldless enum variants For many enums, this avoids generating lots of tiny stubs that need to be codegen'd and then inlined and removed by LLVM. perf shows this to be a fairly small, but significant, win on rustc bootstrap time -- with minimal impact on runtime performance (which is at times even positive).
2 parents 22c2d9d + 3228603 commit 311fa1f

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

compiler/rustc_macros/src/serialize.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -247,13 +247,24 @@ fn encodable_body(
247247
})
248248
.collect();
249249

250-
let result = quote! { ::rustc_serialize::Encoder::emit_enum_variant(
251-
__encoder,
252-
#variant_name,
253-
#variant_idx,
254-
#field_idx,
255-
|__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
256-
) };
250+
let result = if field_idx != 0 {
251+
quote! {
252+
::rustc_serialize::Encoder::emit_enum_variant(
253+
__encoder,
254+
#variant_name,
255+
#variant_idx,
256+
#field_idx,
257+
|__encoder| { ::std::result::Result::Ok({ #encode_fields }) }
258+
)
259+
}
260+
} else {
261+
quote! {
262+
::rustc_serialize::Encoder::emit_fieldless_enum_variant::<#variant_idx>(
263+
__encoder,
264+
#variant_name,
265+
)
266+
}
267+
};
257268
variant_idx += 1;
258269
result
259270
});

compiler/rustc_serialize/src/json.rs

+14
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,13 @@ impl<'a> crate::Encoder for Encoder<'a> {
589589
}
590590
}
591591

592+
fn emit_fieldless_enum_variant<const ID: usize>(
593+
&mut self,
594+
name: &str,
595+
) -> Result<(), Self::Error> {
596+
escape_str(self.writer, name)
597+
}
598+
592599
fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
593600
where
594601
F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
@@ -885,6 +892,13 @@ impl<'a> crate::Encoder for PrettyEncoder<'a> {
885892
}
886893
}
887894

895+
fn emit_fieldless_enum_variant<const ID: usize>(
896+
&mut self,
897+
name: &str,
898+
) -> Result<(), Self::Error> {
899+
escape_str(self.writer, name)
900+
}
901+
888902
fn emit_enum_variant_arg<F>(&mut self, first: bool, f: F) -> EncodeResult
889903
where
890904
F: FnOnce(&mut PrettyEncoder<'a>) -> EncodeResult,

compiler/rustc_serialize/src/serialize.rs

+14
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ pub trait Encoder {
5858
f(self)
5959
}
6060

61+
// We put the field index in a const generic to allow the emit_usize to be
62+
// compiled into a more efficient form. In practice, the variant index is
63+
// known at compile-time, and that knowledge allows much more efficient
64+
// codegen than we'd otherwise get. LLVM isn't always able to make the
65+
// optimization that would otherwise be necessary here, likely due to the
66+
// multiple levels of inlining and const-prop that are needed.
67+
#[inline]
68+
fn emit_fieldless_enum_variant<const ID: usize>(
69+
&mut self,
70+
_v_name: &str,
71+
) -> Result<(), Self::Error> {
72+
self.emit_usize(ID)
73+
}
74+
6175
#[inline]
6276
fn emit_enum_variant_arg<F>(&mut self, _first: bool, f: F) -> Result<(), Self::Error>
6377
where

0 commit comments

Comments
 (0)