Auto merge of #119478 - bjorn3:no_serialize_specialization, r=wesleywiser
Avoid specialization in the metadata serialization code With the exception of a perf-only specialization for byte slices and byte vectors. This uses the same trick of introducing a new trait and having the Encodable and Decodable derives add a bound to it as used for TyEncoder/TyDecoder. The new code is clearer about which encoder/decoder uses which impl and it reduces the dependency of rustc on specialization, making it easier to remove support for specialization entirely or turn it into a construct that is only allowed for perf optimizations if we decide to do this.
This commit is contained in:
commit
e21f4cd98f
24 changed files with 478 additions and 400 deletions
|
@ -26,7 +26,7 @@ use rustc_serialize::{Decodable, Decoder};
|
|||
use rustc_session::cstore::{CrateSource, ExternCrate};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{BytePos, Pos, SpanData, SyntaxContext, DUMMY_SP};
|
||||
use rustc_span::{BytePos, Pos, SpanData, SpanDecoder, SyntaxContext, DUMMY_SP};
|
||||
|
||||
use proc_macro::bridge::client::ProcMacro;
|
||||
use std::iter::TrustedLen;
|
||||
|
@ -408,21 +408,6 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for CrateNum {
|
||||
#[inline]
|
||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> CrateNum {
|
||||
let cnum = CrateNum::from_u32(d.read_u32());
|
||||
d.map_encoded_cnum_to_current(cnum)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefIndex {
|
||||
#[inline]
|
||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefIndex {
|
||||
DefIndex::from_u32(d.read_u32())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex {
|
||||
#[inline]
|
||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex {
|
||||
|
@ -430,19 +415,29 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ast::AttrId {
|
||||
#[inline]
|
||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ast::AttrId {
|
||||
let sess = d.sess.expect("can't decode AttrId without Session");
|
||||
impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> {
|
||||
fn decode_attr_id(&mut self) -> rustc_span::AttrId {
|
||||
let sess = self.sess.expect("can't decode AttrId without Session");
|
||||
sess.parse_sess.attr_id_generator.mk_attr_id()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
|
||||
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext {
|
||||
let cdata = decoder.cdata();
|
||||
fn decode_crate_num(&mut self) -> CrateNum {
|
||||
let cnum = CrateNum::from_u32(self.read_u32());
|
||||
self.map_encoded_cnum_to_current(cnum)
|
||||
}
|
||||
|
||||
let Some(sess) = decoder.sess else {
|
||||
fn decode_def_index(&mut self) -> DefIndex {
|
||||
DefIndex::from_u32(self.read_u32())
|
||||
}
|
||||
|
||||
fn decode_def_id(&mut self) -> DefId {
|
||||
DefId { krate: Decodable::decode(self), index: Decodable::decode(self) }
|
||||
}
|
||||
|
||||
fn decode_syntax_context(&mut self) -> SyntaxContext {
|
||||
let cdata = self.cdata();
|
||||
|
||||
let Some(sess) = self.sess else {
|
||||
bug!(
|
||||
"Cannot decode SyntaxContext without Session.\
|
||||
You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."
|
||||
|
@ -450,7 +445,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
|
|||
};
|
||||
|
||||
let cname = cdata.root.name();
|
||||
rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| {
|
||||
rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| {
|
||||
debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
|
||||
cdata
|
||||
.root
|
||||
|
@ -460,21 +455,19 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
|
|||
.decode((cdata, sess))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
|
||||
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> ExpnId {
|
||||
let local_cdata = decoder.cdata();
|
||||
fn decode_expn_id(&mut self) -> ExpnId {
|
||||
let local_cdata = self.cdata();
|
||||
|
||||
let Some(sess) = decoder.sess else {
|
||||
let Some(sess) = self.sess else {
|
||||
bug!(
|
||||
"Cannot decode ExpnId without Session. \
|
||||
You need to explicitly pass `(crate_metadata_ref, tcx)` to `decode` instead of just `crate_metadata_ref`."
|
||||
);
|
||||
};
|
||||
|
||||
let cnum = CrateNum::decode(decoder);
|
||||
let index = u32::decode(decoder);
|
||||
let cnum = CrateNum::decode(self);
|
||||
let index = u32::decode(self);
|
||||
|
||||
let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| {
|
||||
let ExpnId { krate: cnum, local_id: index } = expn_id;
|
||||
|
@ -502,27 +495,51 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
|
|||
});
|
||||
expn_id
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
|
||||
fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span {
|
||||
let start = decoder.position();
|
||||
let tag = SpanTag(decoder.peek_byte());
|
||||
fn decode_span(&mut self) -> Span {
|
||||
let start = self.position();
|
||||
let tag = SpanTag(self.peek_byte());
|
||||
let data = if tag.kind() == SpanKind::Indirect {
|
||||
// Skip past the tag we just peek'd.
|
||||
decoder.read_u8();
|
||||
let offset_or_position = decoder.read_usize();
|
||||
self.read_u8();
|
||||
let offset_or_position = self.read_usize();
|
||||
let position = if tag.is_relative_offset() {
|
||||
start - offset_or_position
|
||||
} else {
|
||||
offset_or_position
|
||||
};
|
||||
decoder.with_position(position, SpanData::decode)
|
||||
self.with_position(position, SpanData::decode)
|
||||
} else {
|
||||
SpanData::decode(decoder)
|
||||
SpanData::decode(self)
|
||||
};
|
||||
Span::new(data.lo, data.hi, data.ctxt, data.parent)
|
||||
}
|
||||
|
||||
fn decode_symbol(&mut self) -> Symbol {
|
||||
let tag = self.read_u8();
|
||||
|
||||
match tag {
|
||||
SYMBOL_STR => {
|
||||
let s = self.read_str();
|
||||
Symbol::intern(s)
|
||||
}
|
||||
SYMBOL_OFFSET => {
|
||||
// read str offset
|
||||
let pos = self.read_usize();
|
||||
|
||||
// move to str offset and read
|
||||
self.opaque.with_position(pos, |d| {
|
||||
let s = d.read_str();
|
||||
Symbol::intern(s)
|
||||
})
|
||||
}
|
||||
SYMBOL_PREINTERNED => {
|
||||
let symbol_index = self.read_u32();
|
||||
Symbol::new_from_decoded(symbol_index)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData {
|
||||
|
@ -630,34 +647,6 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol {
|
||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
|
||||
let tag = d.read_u8();
|
||||
|
||||
match tag {
|
||||
SYMBOL_STR => {
|
||||
let s = d.read_str();
|
||||
Symbol::intern(s)
|
||||
}
|
||||
SYMBOL_OFFSET => {
|
||||
// read str offset
|
||||
let pos = d.read_usize();
|
||||
|
||||
// move to str offset and read
|
||||
d.opaque.with_position(pos, |d| {
|
||||
let s = d.read_str();
|
||||
Symbol::intern(s)
|
||||
})
|
||||
}
|
||||
SYMBOL_PREINTERNED => {
|
||||
let symbol_index = d.read_u32();
|
||||
Symbol::new_from_decoded(symbol_index)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
|
||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
|
||||
ty::codec::RefDecodable::decode(d)
|
||||
|
|
|
@ -25,7 +25,7 @@ use rustc_session::config::{CrateType, OptLevel};
|
|||
use rustc_span::hygiene::HygieneEncodeContext;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{
|
||||
ExternalSource, FileName, SourceFile, SpanData, StableSourceFileId, SyntaxContext,
|
||||
ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext,
|
||||
};
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
@ -123,70 +123,90 @@ impl<'a, 'tcx, I, T> Encodable<EncodeContext<'a, 'tcx>> for LazyTable<I, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for CrateNum {
|
||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
|
||||
if *self != LOCAL_CRATE && s.is_proc_macro {
|
||||
panic!("Attempted to encode non-local CrateNum {self:?} for proc-macro crate");
|
||||
}
|
||||
s.emit_u32(self.as_u32());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefIndex {
|
||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
|
||||
s.emit_u32(self.as_u32());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnIndex {
|
||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
|
||||
s.emit_u32(self.as_u32());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SyntaxContext {
|
||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
|
||||
rustc_span::hygiene::raw_encode_syntax_context(*self, s.hygiene_ctxt, s);
|
||||
impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> {
|
||||
fn encode_crate_num(&mut self, crate_num: CrateNum) {
|
||||
if crate_num != LOCAL_CRATE && self.is_proc_macro {
|
||||
panic!("Attempted to encode non-local CrateNum {crate_num:?} for proc-macro crate");
|
||||
}
|
||||
self.emit_u32(crate_num.as_u32());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
|
||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
|
||||
if self.krate == LOCAL_CRATE {
|
||||
fn encode_def_index(&mut self, def_index: DefIndex) {
|
||||
self.emit_u32(def_index.as_u32());
|
||||
}
|
||||
|
||||
fn encode_def_id(&mut self, def_id: DefId) {
|
||||
def_id.krate.encode(self);
|
||||
def_id.index.encode(self);
|
||||
}
|
||||
|
||||
fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) {
|
||||
rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_ctxt, self);
|
||||
}
|
||||
|
||||
fn encode_expn_id(&mut self, expn_id: ExpnId) {
|
||||
if expn_id.krate == LOCAL_CRATE {
|
||||
// We will only write details for local expansions. Non-local expansions will fetch
|
||||
// data from the corresponding crate's metadata.
|
||||
// FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external
|
||||
// metadata from proc-macro crates.
|
||||
s.hygiene_ctxt.schedule_expn_data_for_encoding(*self);
|
||||
self.hygiene_ctxt.schedule_expn_data_for_encoding(expn_id);
|
||||
}
|
||||
self.krate.encode(s);
|
||||
self.local_id.encode(s);
|
||||
expn_id.krate.encode(self);
|
||||
expn_id.local_id.encode(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
|
||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
|
||||
match s.span_shorthands.entry(*self) {
|
||||
fn encode_span(&mut self, span: Span) {
|
||||
match self.span_shorthands.entry(span) {
|
||||
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;
|
||||
let offset = self.opaque.position() - last_location;
|
||||
if offset < last_location {
|
||||
SpanTag::indirect(true).encode(s);
|
||||
offset.encode(s);
|
||||
SpanTag::indirect(true).encode(self);
|
||||
offset.encode(self);
|
||||
} else {
|
||||
SpanTag::indirect(false).encode(s);
|
||||
last_location.encode(s);
|
||||
SpanTag::indirect(false).encode(self);
|
||||
last_location.encode(self);
|
||||
}
|
||||
}
|
||||
Entry::Vacant(v) => {
|
||||
let position = s.opaque.position();
|
||||
let position = self.opaque.position();
|
||||
v.insert(position);
|
||||
// Data is encoded with a SpanTag prefix (see below).
|
||||
self.data().encode(s);
|
||||
span.data().encode(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_symbol(&mut self, symbol: Symbol) {
|
||||
// if symbol preinterned, emit tag and symbol index
|
||||
if symbol.is_preinterned() {
|
||||
self.opaque.emit_u8(SYMBOL_PREINTERNED);
|
||||
self.opaque.emit_u32(symbol.as_u32());
|
||||
} else {
|
||||
// otherwise write it as string or as offset to it
|
||||
match self.symbol_table.entry(symbol) {
|
||||
Entry::Vacant(o) => {
|
||||
self.opaque.emit_u8(SYMBOL_STR);
|
||||
let pos = self.opaque.position();
|
||||
o.insert(pos);
|
||||
self.emit_str(symbol.as_str());
|
||||
}
|
||||
Entry::Occupied(o) => {
|
||||
let x = *o.get();
|
||||
self.emit_u8(SYMBOL_OFFSET);
|
||||
self.emit_usize(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -335,31 +355,6 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Symbol {
|
||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
|
||||
// if symbol preinterned, emit tag and symbol index
|
||||
if self.is_preinterned() {
|
||||
s.opaque.emit_u8(SYMBOL_PREINTERNED);
|
||||
s.opaque.emit_u32(self.as_u32());
|
||||
} else {
|
||||
// otherwise write it as string or as offset to it
|
||||
match s.symbol_table.entry(*self) {
|
||||
Entry::Vacant(o) => {
|
||||
s.opaque.emit_u8(SYMBOL_STR);
|
||||
let pos = s.opaque.position();
|
||||
o.insert(pos);
|
||||
s.emit_str(self.as_str());
|
||||
}
|
||||
Entry::Occupied(o) => {
|
||||
let x = *o.get();
|
||||
s.emit_u8(SYMBOL_OFFSET);
|
||||
s.emit_usize(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for [u8] {
|
||||
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
|
||||
Encoder::emit_usize(e, self.len());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue