about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMark Rousskov <mark.simulacrum@gmail.com>2023-12-25 11:49:51 -0500
committerMark Rousskov <mark.simulacrum@gmail.com>2023-12-27 07:31:38 -0500
commit9c5293c27b39be486b6e4b837d18d460600e9c13 (patch)
treed5a01ca920e6024ceb76c9480e58c12e9f6547e4
parent71696e516db31bc3674ba3461ba85e3e0d5bcbe5 (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.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs14
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs3
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,
 }