Skip to content

Commit

Permalink
Support relative offsets when encoding spans
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
Mark-Simulacrum committed Dec 27, 2023
1 parent 71696e5 commit 9c5293c
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 3 deletions.
10 changes: 9 additions & 1 deletion compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down

0 comments on commit 9c5293c

Please sign in to comment.