Skip to content

Commit 2fec2d6

Browse files
Improve coding efficiency for RawDefId
This copies the scheme already used for LazyArray, cutting a couple hundred kilobytes from libcore's metadata.
1 parent 5151b8c commit 2fec2d6

File tree

1 file changed

+36
-23
lines changed
  • compiler/rustc_metadata/src/rmeta

1 file changed

+36
-23
lines changed

compiler/rustc_metadata/src/rmeta/table.rs

+36-23
Original file line numberDiff line numberDiff line change
@@ -240,24 +240,30 @@ impl FixedSizeEncoding for Option<RawDefId> {
240240
type ByteArray = [u8; 8];
241241

242242
#[inline]
243-
fn from_bytes(b: &[u8; 8]) -> Self {
244-
let krate = u32::from_le_bytes(b[0..4].try_into().unwrap());
243+
fn from_bytes(encoded: &[u8; 8]) -> Self {
244+
let (index, krate) = decode_interleaved(encoded);
245+
let krate = u32::from_le_bytes(krate);
245246
if krate == 0 {
246247
return None;
247248
}
248-
let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
249+
let index = u32::from_le_bytes(index);
250+
249251
Some(RawDefId { krate: krate - 1, index })
250252
}
251253

252254
#[inline]
253-
fn write_to_bytes(self, b: &mut [u8; 8]) {
255+
fn write_to_bytes(self, dest: &mut [u8; 8]) {
254256
match self {
255257
None => unreachable!(),
256258
Some(RawDefId { krate, index }) => {
257-
// CrateNum is less than `CrateNum::MAX_AS_U32`.
258259
debug_assert!(krate < u32::MAX);
259-
b[0..4].copy_from_slice(&(1 + krate).to_le_bytes());
260-
b[4..8].copy_from_slice(&index.to_le_bytes());
260+
// CrateNum is less than `CrateNum::MAX_AS_U32`.
261+
let krate = (krate + 1).to_le_bytes();
262+
let index = index.to_le_bytes();
263+
264+
// CrateNum is usually much smaller than the index within the crate, so put it in
265+
// the second slot.
266+
encode_interleaved(index, krate, dest);
261267
}
262268
}
263269
}
@@ -359,20 +365,11 @@ impl<T> FixedSizeEncoding for Option<LazyValue<T>> {
359365

360366
impl<T> LazyArray<T> {
361367
#[inline]
362-
fn write_to_bytes_impl(self, b: &mut [u8; 16]) {
368+
fn write_to_bytes_impl(self, dest: &mut [u8; 16]) {
363369
let position = (self.position.get() as u64).to_le_bytes();
364370
let len = (self.num_elems as u64).to_le_bytes();
365371

366-
// Element width is selected at runtime on a per-table basis by omitting trailing
367-
// zero bytes in table elements. This works very naturally when table elements are
368-
// simple numbers but `LazyArray` is a pair of integers. If naively encoded, the second
369-
// element would shield the trailing zeroes in the first. Interleaving the bytes
370-
// of the position and length exposes trailing zeroes in both to the optimization.
371-
// We encode length second because we generally expect it to be smaller.
372-
for i in 0..8 {
373-
b[2 * i] = position[i];
374-
b[2 * i + 1] = len[i];
375-
}
372+
encode_interleaved(position, len, dest)
376373
}
377374

378375
fn from_bytes_impl(position: &[u8; 8], meta: &[u8; 8]) -> Option<LazyArray<T>> {
@@ -382,20 +379,36 @@ impl<T> LazyArray<T> {
382379
}
383380
}
384381

385-
// Decoding helper for the encoding scheme used by `LazyArray`.
386382
// Interleaving the bytes of the two integers exposes trailing bytes in the first integer
387383
// to the varint scheme that we use for tables.
388384
#[inline]
389-
fn decode_interleaved(encoded: &[u8; 16]) -> ([u8; 8], [u8; 8]) {
390-
let mut first = [0u8; 8];
391-
let mut second = [0u8; 8];
392-
for i in 0..8 {
385+
fn decode_interleaved<const N: usize, const M: usize>(encoded: &[u8; N]) -> ([u8; M], [u8; M]) {
386+
assert_eq!(M * 2, N);
387+
let mut first = [0u8; M];
388+
let mut second = [0u8; M];
389+
for i in 0..M {
393390
first[i] = encoded[2 * i];
394391
second[i] = encoded[2 * i + 1];
395392
}
396393
(first, second)
397394
}
398395

396+
// Element width is selected at runtime on a per-table basis by omitting trailing
397+
// zero bytes in table elements. This works very naturally when table elements are
398+
// simple numbers but sometimes we have a pair of integers. If naively encoded, the second element
399+
// would shield the trailing zeroes in the first. Interleaving the bytes exposes trailing zeroes in
400+
// both to the optimization.
401+
//
402+
// Prefer passing a and b such that `b` is usually smaller.
403+
#[inline]
404+
fn encode_interleaved<const N: usize, const M: usize>(a: [u8; M], b: [u8; M], dest: &mut [u8; N]) {
405+
assert_eq!(M * 2, N);
406+
for i in 0..M {
407+
dest[2 * i] = a[i];
408+
dest[2 * i + 1] = b[i];
409+
}
410+
}
411+
399412
impl<T> FixedSizeEncoding for LazyArray<T> {
400413
type ByteArray = [u8; 16];
401414

0 commit comments

Comments
 (0)