Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 45d702d

Browse files
committedFeb 17, 2025
Add a .bss-like scheme for encoded const allocs
1 parent 2162e9d commit 45d702d

File tree

1 file changed

+93
-2
lines changed

1 file changed

+93
-2
lines changed
 

‎compiler/rustc_middle/src/mir/interpret/allocation.rs

+93-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use provenance_map::*;
1515
use rustc_abi::{Align, HasDataLayout, Size};
1616
use rustc_ast::Mutability;
1717
use rustc_data_structures::intern::Interned;
18-
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
18+
use rustc_macros::HashStable;
19+
use rustc_serialize::{Decodable, Encodable};
20+
use rustc_type_ir::{TyDecoder, TyEncoder};
1921

2022
use super::{
2123
AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer,
@@ -77,7 +79,7 @@ impl AllocBytes for Box<[u8]> {
7779
/// module provides higher-level access.
7880
// Note: for performance reasons when interning, some of the `Allocation` fields can be partially
7981
// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
80-
#[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
82+
#[derive(Clone, Eq, PartialEq)]
8183
#[derive(HashStable)]
8284
pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box<[u8]>> {
8385
/// The actual bytes of the allocation.
@@ -101,6 +103,95 @@ pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box
101103
pub extra: Extra,
102104
}
103105

106+
/// Helper struct that packs an alignment, mutability, and "all bytes are zero" flag together.
107+
///
108+
/// Alignment values always have 2 free high bits.
109+
struct AllocFlags {
110+
align: Align,
111+
mutability: Mutability,
112+
all_zero: bool,
113+
}
114+
115+
impl<E: TyEncoder> Encodable<E> for AllocFlags {
116+
fn encode(&self, encoder: &mut E) {
117+
let mut flags = self.align.bytes().trailing_zeros() as u8;
118+
flags |= match self.mutability {
119+
Mutability::Not => 0,
120+
Mutability::Mut => 1 << 6,
121+
};
122+
flags |= (self.all_zero as u8) << 7;
123+
flags.encode(encoder);
124+
}
125+
}
126+
127+
impl<D: TyDecoder> Decodable<D> for AllocFlags {
128+
fn decode(decoder: &mut D) -> Self {
129+
let flags: u8 = Decodable::decode(decoder);
130+
let align = flags & 0b0011_1111;
131+
let mutability = flags & 0b0100_0000;
132+
let all_zero = flags & 0b1000_0000;
133+
134+
let align = Align::from_bytes(1 << align).unwrap();
135+
let mutability = match mutability {
136+
0 => Mutability::Not,
137+
_ => Mutability::Mut,
138+
};
139+
let all_zero = all_zero > 0;
140+
141+
AllocFlags { align, mutability, all_zero }
142+
}
143+
}
144+
145+
#[inline]
146+
fn all_zero(buf: &[u8]) -> bool {
147+
let mut fold = 0;
148+
for b in buf.iter() {
149+
fold |= *b;
150+
}
151+
fold == 0
152+
}
153+
154+
impl<Prov: Provenance, Extra, Bytes, E: TyEncoder> Encodable<E> for Allocation<Prov, Extra, Bytes>
155+
where
156+
Bytes: AllocBytes,
157+
ProvenanceMap<Prov>: Encodable<E>,
158+
Extra: Encodable<E>,
159+
{
160+
fn encode(&self, encoder: &mut E) {
161+
let all_zero = all_zero(&self.bytes);
162+
AllocFlags { align: self.align, mutability: self.mutability, all_zero }.encode(encoder);
163+
164+
encoder.emit_usize(self.bytes.len());
165+
if !all_zero {
166+
encoder.emit_raw_bytes(&self.bytes);
167+
}
168+
self.provenance.encode(encoder);
169+
self.init_mask.encode(encoder);
170+
self.extra.encode(encoder);
171+
}
172+
}
173+
174+
impl<Prov: Provenance, Extra, Bytes, D: TyDecoder> Decodable<D> for Allocation<Prov, Extra, Bytes>
175+
where
176+
Bytes: AllocBytes,
177+
ProvenanceMap<Prov>: Decodable<D>,
178+
Extra: Decodable<D>,
179+
{
180+
fn decode(decoder: &mut D) -> Self {
181+
let AllocFlags { align, mutability, all_zero } = Decodable::decode(decoder);
182+
183+
let len = decoder.read_usize();
184+
let bytes = if all_zero { vec![0u8; len] } else { decoder.read_raw_bytes(len).to_vec() };
185+
let bytes = Bytes::from_bytes(bytes, align);
186+
187+
let provenance = Decodable::decode(decoder);
188+
let init_mask = Decodable::decode(decoder);
189+
let extra = Decodable::decode(decoder);
190+
191+
Self { bytes, provenance, init_mask, align, mutability, extra }
192+
}
193+
}
194+
104195
/// This is the maximum size we will hash at a time, when interning an `Allocation` and its
105196
/// `InitMask`. Note, we hash that amount of bytes twice: at the start, and at the end of a buffer.
106197
/// Used when these two structures are large: we only partially hash the larger fields in that

0 commit comments

Comments
 (0)
Failed to load comments.