1
Fork 0

Use delayed error handling for Encodable and Encoder infallible.

There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.

Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).

This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.

This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.

Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
  `into_inner` method is changed into `finish`, which returns
  `Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
  strategy. Its `Ok` type is a `usize`, returning the number of bytes
  written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
  passed a mutable reference, e.g. `serialize_query_result_cache`.
This commit is contained in:
Nicholas Nethercote 2022-06-07 13:30:45 +10:00
parent 582b9cbc45
commit 1acbe7573d
45 changed files with 611 additions and 682 deletions

View file

@ -4,7 +4,7 @@ use crate::rmeta::MetadataBlob;
use rustc_data_structures::owning_ref::OwningRef;
use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
use rustc_middle::parameterized_over_tcx;
use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::def_id::{DefIndex, DefPathHash};
pub(crate) enum DefPathHashMapRef<'tcx> {
@ -29,12 +29,12 @@ impl DefPathHashMapRef<'_> {
}
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
match *self {
DefPathHashMapRef::BorrowedFromTcx(def_path_hash_map) => {
let bytes = def_path_hash_map.raw_bytes();
e.emit_usize(bytes.len())?;
e.emit_raw_bytes(bytes)
e.emit_usize(bytes.len());
e.emit_raw_bytes(bytes);
}
DefPathHashMapRef::OwnedFromMetadata(_) => {
panic!("DefPathHashMap::OwnedFromMetadata variant only exists for deserialization")

View file

@ -86,14 +86,15 @@ macro_rules! empty_proc_macro {
macro_rules! encoder_methods {
($($name:ident($ty:ty);)*) => {
$(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
$(fn $name(&mut self, value: $ty) {
self.opaque.$name(value)
})*
}
}
impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
type Error = <opaque::Encoder as Encoder>::Error;
type Ok = <opaque::Encoder as Encoder>::Ok;
type Err = <opaque::Encoder as Encoder>::Err;
encoder_methods! {
emit_usize(usize);
@ -117,60 +118,63 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
emit_str(&str);
emit_raw_bytes(&[u8]);
}
fn finish(self) -> Result<Self::Ok, Self::Err> {
self.opaque.finish()
}
}
impl<'a, 'tcx, T> Encodable<EncodeContext<'a, 'tcx>> for LazyValue<T> {
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
e.emit_lazy_distance(self.position)
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
e.emit_lazy_distance(self.position);
}
}
impl<'a, 'tcx, T> Encodable<EncodeContext<'a, 'tcx>> for LazyArray<T> {
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
e.emit_usize(self.num_elems)?;
if self.num_elems == 0 {
return Ok(());
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
e.emit_usize(self.num_elems);
if self.num_elems > 0 {
e.emit_lazy_distance(self.position)
}
e.emit_lazy_distance(self.position)
}
}
impl<'a, 'tcx, I, T> Encodable<EncodeContext<'a, 'tcx>> for LazyTable<I, T> {
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
e.emit_usize(self.encoded_size)?;
e.emit_lazy_distance(self.position)
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
e.emit_usize(self.encoded_size);
e.emit_lazy_distance(self.position);
}
}
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for CrateNum {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
if *self != LOCAL_CRATE && s.is_proc_macro {
panic!("Attempted to encode non-local CrateNum {:?} for proc-macro crate", self);
}
s.emit_u32(self.as_u32())
s.emit_u32(self.as_u32());
}
}
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefIndex {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
s.emit_u32(self.as_u32())
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>) -> opaque::EncodeResult {
s.emit_u32(self.as_u32())
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>) -> opaque::EncodeResult {
rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s)
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
rustc_span::hygiene::raw_encode_syntax_context(*self, &s.hygiene_ctxt, s);
}
}
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
if self.krate == LOCAL_CRATE {
// We will only write details for local expansions. Non-local expansions will fetch
// data from the corresponding crate's metadata.
@ -178,13 +182,13 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
// metadata from proc-macro crates.
s.hygiene_ctxt.schedule_expn_data_for_encoding(*self);
}
self.krate.encode(s)?;
self.local_id.encode(s)
self.krate.encode(s);
self.local_id.encode(s);
}
}
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
let span = self.data();
// Don't serialize any `SyntaxContext`s from a proc-macro crate,
@ -219,9 +223,9 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
// `rustc_span::hygiene::raw_encode_expn_id` to handle
// encoding `ExpnData` for proc-macro crates.
if s.is_proc_macro {
SyntaxContext::root().encode(s)?;
SyntaxContext::root().encode(s);
} else {
span.ctxt.encode(s)?;
span.ctxt.encode(s);
}
if self.is_dummy() {
@ -289,22 +293,20 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
(TAG_VALID_SPAN_LOCAL, span.lo, span.hi)
};
tag.encode(s)?;
lo.encode(s)?;
tag.encode(s);
lo.encode(s);
// Encode length which is usually less than span.hi and profits more
// from the variable-length integer encoding that we use.
let len = hi - lo;
len.encode(s)?;
len.encode(s);
if tag == TAG_VALID_SPAN_FOREIGN {
// This needs to be two lines to avoid holding the `s.source_file_cache`
// while calling `cnum.encode(s)`
let cnum = s.source_file_cache.0.cnum;
cnum.encode(s)?;
cnum.encode(s);
}
Ok(())
}
}
@ -325,13 +327,10 @@ impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
&mut self.predicate_shorthands
}
fn encode_alloc_id(
&mut self,
alloc_id: &rustc_middle::mir::interpret::AllocId,
) -> Result<(), Self::Error> {
fn encode_alloc_id(&mut self, alloc_id: &rustc_middle::mir::interpret::AllocId) {
let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
index.encode(self)
index.encode(self);
}
}
@ -360,10 +359,7 @@ macro_rules! record_array {
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn emit_lazy_distance(
&mut self,
position: NonZeroUsize,
) -> Result<(), <Self as Encoder>::Error> {
fn emit_lazy_distance(&mut self, position: NonZeroUsize) {
let pos = position.get();
let distance = match self.lazy_state {
LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
@ -382,7 +378,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
};
self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap());
self.emit_usize(distance)
self.emit_usize(distance);
}
fn lazy<T: ParameterizedOverTcx, B: Borrow<T::Value<'tcx>>>(&mut self, value: B) -> LazyValue<T>
@ -393,7 +389,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
assert_eq!(self.lazy_state, LazyState::NoNode);
self.lazy_state = LazyState::NodeStart(pos);
value.borrow().encode(self).unwrap();
value.borrow().encode(self);
self.lazy_state = LazyState::NoNode;
assert!(pos.get() <= self.position());
@ -412,7 +408,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
assert_eq!(self.lazy_state, LazyState::NoNode);
self.lazy_state = LazyState::NodeStart(pos);
let len = values.into_iter().map(|value| value.borrow().encode(self).unwrap()).count();
let len = values.into_iter().map(|value| value.borrow().encode(self)).count();
self.lazy_state = LazyState::NoNode;
assert!(pos.get() <= self.position());
@ -615,7 +611,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let id = self.interpret_allocs[idx];
let pos = self.position() as u32;
interpret_alloc_index.push(pos);
interpret::specialized_encode_alloc_id(self, tcx, id).unwrap();
interpret::specialized_encode_alloc_id(self, tcx, id);
}
n = new_n;
}
@ -1640,18 +1636,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let mut expn_data_table: TableBuilder<_, _> = Default::default();
let mut expn_hash_table: TableBuilder<_, _> = Default::default();
let _: Result<(), !> = self.hygiene_ctxt.encode(
self.hygiene_ctxt.encode(
&mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table),
|(this, syntax_contexts, _, _), index, ctxt_data| {
syntax_contexts.set(index, this.lazy(ctxt_data));
Ok(())
},
|(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| {
if let Some(index) = index.as_local() {
expn_data_table.set(index.as_raw(), this.lazy(expn_data));
expn_hash_table.set(index.as_raw(), this.lazy(hash));
}
Ok(())
},
);
@ -2195,10 +2189,10 @@ pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
let mut encoder = opaque::Encoder::new();
encoder.emit_raw_bytes(METADATA_HEADER).unwrap();
encoder.emit_raw_bytes(METADATA_HEADER);
// Will be filled with the root position after encoding everything.
encoder.emit_raw_bytes(&[0, 0, 0, 0]).unwrap();
encoder.emit_raw_bytes(&[0, 0, 0, 0]);
let source_map_files = tcx.sess.source_map().files();
let source_file_cache = (source_map_files[0].clone(), 0);
@ -2223,13 +2217,13 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
};
// Encode the rustc version string in a predictable location.
rustc_version().encode(&mut ecx).unwrap();
rustc_version().encode(&mut ecx);
// Encode all the entries and extra information in the crate,
// culminating in the `CrateRoot` which points to all of it.
let root = ecx.encode_crate_root();
let mut result = ecx.opaque.into_inner();
let mut result = ecx.opaque.finish().unwrap();
// Encode the root position.
let header = METADATA_HEADER.len();

View file

@ -287,7 +287,7 @@ where
{
let pos = buf.position();
for block in &self.blocks {
buf.emit_raw_bytes(block).unwrap();
buf.emit_raw_bytes(block);
}
let num_bytes = self.blocks.len() * N;
LazyTable::from_position_and_encoded_size(