diff options
| author | Mark Rousskov <mark.simulacrum@gmail.com> | 2023-12-25 11:49:51 -0500 |
|---|---|---|
| committer | Mark Rousskov <mark.simulacrum@gmail.com> | 2023-12-27 07:31:38 -0500 |
| commit | 9c5293c27b39be486b6e4b837d18d460600e9c13 (patch) | |
| tree | d5a01ca920e6024ceb76c9480e58c12e9f6547e4 | |
| parent | 71696e516db31bc3674ba3461ba85e3e0d5bcbe5 (diff) | |
Support relative offsets when encoding spans
The relative offset is often smaller than the absolute offset, and with the LEB128 encoding, this ends up cutting the overall metadata size considerably (~1.5 megabytes on libcore). We can support both relative and absolute encodings essentially for free since we already take a full byte to differentiate between direct and indirect encodings (so an extra variant is quite cheap).
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/decoder.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/encoder.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_metadata/src/rmeta/mod.rs | 3 |
3 files changed, 24 insertions, 3 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 55daf441a75..ae4a0e15fab 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -507,10 +507,18 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId { impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span { + let start = decoder.position(); let mode = SpanEncodingMode::decode(decoder); let data = match mode { SpanEncodingMode::Direct => SpanData::decode(decoder), - SpanEncodingMode::Shorthand(position) => decoder.with_position(position, |decoder| { + SpanEncodingMode::RelativeOffset(offset) => { + decoder.with_position(start - offset, |decoder| { + let mode = SpanEncodingMode::decode(decoder); + debug_assert!(matches!(mode, SpanEncodingMode::Direct)); + SpanData::decode(decoder) + }) + } + SpanEncodingMode::AbsoluteOffset(addr) => decoder.with_position(addr, |decoder| { let mode = SpanEncodingMode::decode(decoder); debug_assert!(matches!(mode, SpanEncodingMode::Direct)); SpanData::decode(decoder) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 411a70f9f1b..513c49efc8e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -169,7 +169,19 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId { impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { match s.span_shorthands.entry(*self) { - Entry::Occupied(o) => SpanEncodingMode::Shorthand(*o.get()).encode(s), + Entry::Occupied(o) => { + // If an offset is smaller than the absolute position, we encode with the offset. + // This saves space since smaller numbers encode in less bits. + let last_location = *o.get(); + // This cannot underflow. Metadata is written with increasing position(), so any + // previously saved offset must be smaller than the current position. + let offset = s.opaque.position() - last_location; + if offset < last_location { + SpanEncodingMode::RelativeOffset(offset).encode(s) + } else { + SpanEncodingMode::AbsoluteOffset(last_location).encode(s) + } + } Entry::Vacant(v) => { let position = s.opaque.position(); v.insert(position); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index d496e7494e7..bafd3f0b84d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -68,7 +68,8 @@ pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_V #[derive(Encodable, Decodable)] enum SpanEncodingMode { - Shorthand(usize), + RelativeOffset(usize), + AbsoluteOffset(usize), Direct, } |
