diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index 01efcaf6f448d8f59778dce8a3e8989bd50fd441..8afe94ac8dba845679f30ed04bae4b2128317dde 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -4,7 +4,7 @@ Decodable, Encodable, }; use std::hash::{Hash, Hasher}; -use std::mem; +use std::mem::{self, MaybeUninit}; #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)] pub struct Fingerprint(u64, u64); @@ -61,7 +61,7 @@ pub fn encode_opaque(&self, encoder: &mut opaque::Encoder) -> EncodeResult { } pub fn decode_opaque(decoder: &mut opaque::Decoder<'_>) -> Result { - let mut bytes = [0; 16]; + let mut bytes: [MaybeUninit; 16] = MaybeUninit::uninit_array(); decoder.read_raw_bytes(&mut bytes)?; diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index dbeb3c755044f543bdb2a64eceea3bc5f4ae7e2b..72bd4804e98c0b81e4f5e20a6228db87f74e07a6 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -203,7 +203,7 @@ fn encodable_body( #field_name, #field_idx, |__encoder| - ::rustc_serialize::Encodable::encode(#bind_ident, __encoder), + ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder), ) { ::std::result::Result::Ok(()) => (), ::std::result::Result::Err(__err) @@ -237,7 +237,7 @@ fn encodable_body( __encoder, #field_idx, |__encoder| - ::rustc_serialize::Encodable::encode(#bind_ident, __encoder), + ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder), ) { ::std::result::Result::Ok(()) => (), ::std::result::Result::Err(__err) diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 8a1165bbd647a296bf8fc19ff2fdb387976e959c..9b40c9a7ed88ad42a7f2cf9942787af37e61e5b5 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -807,6 +807,15 @@ fn decode_alloc_id(&mut self) -> Result { crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>); +// This ensures that the `Decodable::decode` specialization for `Vec` is used +// when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt +// into specializations this way, given how `CacheDecoder` and the decoding traits currently work. +impl<'a, 'tcx> Decodable> for Vec { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { + Decodable::decode(&mut d.opaque) + } +} + impl<'a, 'tcx> Decodable> for SyntaxContext { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { let syntax_contexts = decoder.syntax_contexts; @@ -1149,6 +1158,16 @@ fn emit_unit(&mut self) -> Result<(), Self::Error> { } } +// This ensures that the `Encodable::encode` specialization for byte slices +// is used when a `CacheEncoder` having an `opaque::Encoder` is passed to `Encodable::encode`. +// Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder` +// and the encoding traits currently work. +impl<'a, 'tcx> Encodable> for [u8] { + fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, opaque::Encoder>) -> opaque::EncodeResult { + self.encode(e.encoder) + } +} + // An integer that will always encode to 8 bytes. struct IntEncodedWithFixedSize(u64); diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs index 3d274cb01507b004bcde7191709a66c6c6bb4ed4..ae6d27e037b2dbda7a1f66ffa7712a4c0de77381 100644 --- a/compiler/rustc_serialize/src/collection_impls.rs +++ b/compiler/rustc_serialize/src/collection_impls.rs @@ -11,12 +11,8 @@ impl>> Encodable for SmallVec { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))?; - } - Ok(()) - }) + let slice: &[A::Item] = self; + slice.encode(s) } } @@ -292,46 +288,28 @@ fn decode(d: &mut D) -> Result, D::Error> { impl> Encodable for Rc<[T]> { fn encode(&self, s: &mut E) -> Result<(), E::Error> { - s.emit_seq(self.len(), |s| { - for (index, e) in self.iter().enumerate() { - s.emit_seq_elt(index, |s| e.encode(s))?; - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } impl> Decodable for Rc<[T]> { fn decode(d: &mut D) -> Result, D::Error> { - d.read_seq(|d, len| { - let mut vec = Vec::with_capacity(len); - for index in 0..len { - vec.push(d.read_seq_elt(index, |d| Decodable::decode(d))?); - } - Ok(vec.into()) - }) + let vec: Vec = Decodable::decode(d)?; + Ok(vec.into()) } } impl> Encodable for Arc<[T]> { fn encode(&self, s: &mut E) -> Result<(), E::Error> { - s.emit_seq(self.len(), |s| { - for (index, e) in self.iter().enumerate() { - s.emit_seq_elt(index, |s| e.encode(s))?; - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } impl> Decodable for Arc<[T]> { fn decode(d: &mut D) -> Result, D::Error> { - d.read_seq(|d, len| { - let mut vec = Vec::with_capacity(len); - for index in 0..len { - vec.push(d.read_seq_elt(index, |d| Decodable::decode(d))?); - } - Ok(vec.into()) - }) + let vec: Vec = Decodable::decode(d)?; + Ok(vec.into()) } } diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index ac1cdc6ad45f20338a8ad3ba8d55bed26304ab11..f58ed14d9971e09103241349f806c83484c8f162 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -14,6 +14,8 @@ #![feature(nll)] #![feature(associated_type_bounds)] #![cfg_attr(bootstrap, feature(min_const_generics))] +#![feature(min_specialization)] +#![feature(vec_spare_capacity)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 8b79c93e7605bf98b706175f06616b37d4eb0aff..673742df7f0dce75c3e99508075c1813e448becd 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -1,6 +1,8 @@ use crate::leb128::{self, read_signed_leb128, write_signed_leb128}; use crate::serialize; use std::borrow::Cow; +use std::mem::MaybeUninit; +use std::ptr; // ----------------------------------------------------------------------------- // Encoder @@ -179,11 +181,19 @@ pub fn advance(&mut self, bytes: usize) { } #[inline] - pub fn read_raw_bytes(&mut self, s: &mut [u8]) -> Result<(), String> { + pub fn read_raw_bytes(&mut self, s: &mut [MaybeUninit]) -> Result<(), String> { let start = self.position; let end = start + s.len(); + assert!(end <= self.data.len()); - s.copy_from_slice(&self.data[start..end]); + // SAFETY: Both `src` and `dst` point to at least `s.len()` elements: + // `src` points to at least `s.len()` elements by above assert, and + // `dst` points to `s.len()` elements by derivation from `s`. + unsafe { + let src = self.data.as_ptr().add(start); + let dst = s.as_mut_ptr() as *mut u8; + ptr::copy_nonoverlapping(src, dst, s.len()); + } self.position = end; @@ -316,3 +326,36 @@ fn error(&mut self, err: &str) -> Self::Error { err.to_string() } } + +// Specializations for contiguous byte sequences follow. The default implementations for slices +// encode and decode each element individually. This isn't necessary for `u8` slices when using +// opaque encoders and decoders, because each `u8` is unchanged by encoding and decoding. +// Therefore, we can use more efficient implementations that process the entire sequence at once. + +// Specialize encoding byte slices. This specialization also applies to encoding `Vec`s, etc., +// since the default implementations call `encode` on their slices internally. +impl serialize::Encodable for [u8] { + fn encode(&self, e: &mut Encoder) -> EncodeResult { + serialize::Encoder::emit_usize(e, self.len())?; + e.emit_raw_bytes(self); + Ok(()) + } +} + +// Specialize decoding `Vec`. This specialization also applies to decoding `Box<[u8]>`s, etc., +// since the default implementations call `decode` to produce a `Vec` internally. +impl<'a> serialize::Decodable> for Vec { + fn decode(d: &mut Decoder<'a>) -> Result { + let len = serialize::Decoder::read_usize(d)?; + + let mut v = Vec::with_capacity(len); + let buf = &mut v.spare_capacity_mut()[..len]; + d.read_raw_bytes(buf)?; + + unsafe { + v.set_len(len); + } + + Ok(v) + } +} diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index aa305f3c7fc3f7c69b5f485ecc7c04cd2c3b1943..47aad5b88c6229dc5532f820c575007354af80b1 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -527,7 +527,7 @@ fn decode(d: &mut D) -> Result, D::Error> { } impl> Encodable for [T] { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { + default fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { for (i, e) in self.iter().enumerate() { s.emit_seq_elt(i, |s| e.encode(s))? @@ -545,7 +545,7 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> { } impl> Decodable for Vec { - fn decode(d: &mut D) -> Result, D::Error> { + default fn decode(d: &mut D) -> Result, D::Error> { d.read_seq(|d, len| { let mut v = Vec::with_capacity(len); for i in 0..len { @@ -591,13 +591,8 @@ impl + ToOwned> Decodable for Cow<'static, [T]> [T]: ToOwned>, { fn decode(d: &mut D) -> Result, D::Error> { - d.read_seq(|d, len| { - let mut v = Vec::with_capacity(len); - for i in 0..len { - v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); - } - Ok(Cow::Owned(v)) - }) + let v: Vec = Decodable::decode(d)?; + Ok(Cow::Owned(v)) } }