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).
This commit is contained in:
parent
71696e516d
commit
9c5293c27b
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user