Rollup merge of #111086 - nnethercote:rm-MemEncoder, r=cjgillot

Remove `MemEncoder`

`MemEncoder` only has one non-test use, and `FileEncoder` would be more appropriate there anyway.

r? ``@cjgillot``
This commit is contained in:
Dylan DPC 2023-05-04 00:17:26 +05:30 committed by GitHub
commit 887dffc447
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 63 additions and 248 deletions

View File

@ -4060,6 +4060,7 @@ dependencies = [
"indexmap", "indexmap",
"rustc_macros", "rustc_macros",
"smallvec", "smallvec",
"tempfile",
"thin-vec", "thin-vec",
] ]

View File

@ -31,7 +31,7 @@
use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_serialize::opaque::{MemDecoder, MemEncoder}; use rustc_serialize::opaque::{FileEncoder, MemDecoder};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::cstore::{self, CrateSource}; use rustc_session::cstore::{self, CrateSource};
@ -39,6 +39,7 @@
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_span::DebuggerVisualizerFile; use rustc_span::DebuggerVisualizerFile;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
pub mod back; pub mod back;
@ -215,8 +216,11 @@ pub fn looks_like_rust_object_file(filename: &str) -> bool {
const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
impl CodegenResults { impl CodegenResults {
pub fn serialize_rlink(codegen_results: &CodegenResults) -> Vec<u8> { pub fn serialize_rlink(
let mut encoder = MemEncoder::new(); rlink_file: &Path,
codegen_results: &CodegenResults,
) -> Result<usize, io::Error> {
let mut encoder = FileEncoder::new(rlink_file)?;
encoder.emit_raw_bytes(RLINK_MAGIC); encoder.emit_raw_bytes(RLINK_MAGIC);
// `emit_raw_bytes` is used to make sure that the version representation does not depend on // `emit_raw_bytes` is used to make sure that the version representation does not depend on
// Encoder's inner representation of `u32`. // Encoder's inner representation of `u32`.

View File

@ -368,9 +368,8 @@ pub fn link(self) -> Result<()> {
} }
if sess.opts.unstable_opts.no_link { if sess.opts.unstable_opts.no_link {
let encoded = CodegenResults::serialize_rlink(&codegen_results);
let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
std::fs::write(&rlink_file, encoded) CodegenResults::serialize_rlink(&rlink_file, &codegen_results)
.map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?;
return Ok(()); return Ok(());
} }

View File

@ -10,3 +10,4 @@ thin-vec = "0.2.12"
[dev-dependencies] [dev-dependencies]
rustc_macros = { path = "../rustc_macros" } rustc_macros = { path = "../rustc_macros" }
tempfile = "3.2"

View File

@ -12,118 +12,14 @@
// Encoder // Encoder
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
pub struct MemEncoder {
pub data: Vec<u8>,
}
impl MemEncoder {
pub fn new() -> MemEncoder {
MemEncoder { data: vec![] }
}
#[inline]
pub fn position(&self) -> usize {
self.data.len()
}
pub fn finish(self) -> Vec<u8> {
self.data
}
}
macro_rules! write_leb128 {
($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
let old_len = $enc.data.len();
if MAX_ENCODED_LEN > $enc.data.capacity() - old_len {
$enc.data.reserve(MAX_ENCODED_LEN);
}
// SAFETY: The above check and `reserve` ensures that there is enough
// room to write the encoded value to the vector's internal buffer.
unsafe {
let buf = &mut *($enc.data.as_mut_ptr().add(old_len)
as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN]);
let encoded = leb128::$fun(buf, $value);
$enc.data.set_len(old_len + encoded.len());
}
}};
}
impl Encoder for MemEncoder {
#[inline]
fn emit_usize(&mut self, v: usize) {
write_leb128!(self, v, usize, write_usize_leb128)
}
#[inline]
fn emit_u128(&mut self, v: u128) {
write_leb128!(self, v, u128, write_u128_leb128);
}
#[inline]
fn emit_u64(&mut self, v: u64) {
write_leb128!(self, v, u64, write_u64_leb128);
}
#[inline]
fn emit_u32(&mut self, v: u32) {
write_leb128!(self, v, u32, write_u32_leb128);
}
#[inline]
fn emit_u16(&mut self, v: u16) {
self.data.extend_from_slice(&v.to_le_bytes());
}
#[inline]
fn emit_u8(&mut self, v: u8) {
self.data.push(v);
}
#[inline]
fn emit_isize(&mut self, v: isize) {
write_leb128!(self, v, isize, write_isize_leb128)
}
#[inline]
fn emit_i128(&mut self, v: i128) {
write_leb128!(self, v, i128, write_i128_leb128)
}
#[inline]
fn emit_i64(&mut self, v: i64) {
write_leb128!(self, v, i64, write_i64_leb128)
}
#[inline]
fn emit_i32(&mut self, v: i32) {
write_leb128!(self, v, i32, write_i32_leb128)
}
#[inline]
fn emit_i16(&mut self, v: i16) {
self.data.extend_from_slice(&v.to_le_bytes());
}
#[inline]
fn emit_raw_bytes(&mut self, s: &[u8]) {
self.data.extend_from_slice(s);
}
}
pub type FileEncodeResult = Result<usize, io::Error>; pub type FileEncodeResult = Result<usize, io::Error>;
/// `FileEncoder` encodes data to file via fixed-size buffer. /// `FileEncoder` encodes data to file via fixed-size buffer.
/// ///
/// When encoding large amounts of data to a file, using `FileEncoder` may be /// There used to be a `MemEncoder` type that encoded all the data into a
/// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the /// `Vec`. `FileEncoder` is better because its memory use is determined by the
/// `Vec` to file, as the latter uses as much memory as there is encoded data, /// size of the buffer, rather than the full length of the encoded data, and
/// while the former uses the fixed amount of memory allocated to the buffer. /// because it doesn't need to reallocate memory along the way.
/// `FileEncoder` also has the advantage of not needing to reallocate as data
/// is appended to it, but the disadvantage of requiring more error handling,
/// which has some runtime overhead.
pub struct FileEncoder { pub struct FileEncoder {
/// The input buffer. For adequate performance, we need more control over /// The input buffer. For adequate performance, we need more control over
/// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw /// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
@ -645,13 +541,6 @@ fn peek_byte(&self) -> u8 {
// Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc., // Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc.,
// since the default implementations call `encode` on their slices internally. // since the default implementations call `encode` on their slices internally.
impl Encodable<MemEncoder> for [u8] {
fn encode(&self, e: &mut MemEncoder) {
Encoder::emit_usize(e, self.len());
e.emit_raw_bytes(self);
}
}
impl Encodable<FileEncoder> for [u8] { impl Encodable<FileEncoder> for [u8] {
fn encode(&self, e: &mut FileEncoder) { fn encode(&self, e: &mut FileEncoder) {
Encoder::emit_usize(e, self.len()); Encoder::emit_usize(e, self.len());
@ -675,16 +564,6 @@ impl IntEncodedWithFixedSize {
pub const ENCODED_SIZE: usize = 8; pub const ENCODED_SIZE: usize = 8;
} }
impl Encodable<MemEncoder> for IntEncodedWithFixedSize {
#[inline]
fn encode(&self, e: &mut MemEncoder) {
let _start_pos = e.position();
e.emit_raw_bytes(&self.0.to_le_bytes());
let _end_pos = e.position();
debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
}
}
impl Encodable<FileEncoder> for IntEncodedWithFixedSize { impl Encodable<FileEncoder> for IntEncodedWithFixedSize {
#[inline] #[inline]
fn encode(&self, e: &mut FileEncoder) { fn encode(&self, e: &mut FileEncoder) {

View File

@ -1,9 +1,10 @@
#![allow(rustc::internal)] #![allow(rustc::internal)]
use rustc_macros::{Decodable, Encodable}; use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder}; use rustc_serialize::opaque::{MemDecoder, FileEncoder};
use rustc_serialize::{Decodable, Encodable}; use rustc_serialize::{Decodable, Encodable};
use std::fmt::Debug; use std::fmt::Debug;
use std::fs;
#[derive(PartialEq, Clone, Debug, Encodable, Decodable)] #[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
struct Struct { struct Struct {
@ -27,18 +28,21 @@ struct Struct {
} }
fn check_round_trip< fn check_round_trip<
T: Encodable<MemEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug, T: Encodable<FileEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug,
>( >(
values: Vec<T>, values: Vec<T>,
) { ) {
let mut encoder = MemEncoder::new(); let tmpfile = tempfile::NamedTempFile::new().unwrap();
let tmpfile = tmpfile.path();
let mut encoder = FileEncoder::new(&tmpfile).unwrap();
for value in &values { for value in &values {
Encodable::encode(value, &mut encoder); Encodable::encode(value, &mut encoder);
} }
encoder.finish().unwrap();
let data = encoder.finish(); let data = fs::read(&tmpfile).unwrap();
let mut decoder = MemDecoder::new(&data[..], 0); let mut decoder = MemDecoder::new(&data[..], 0);
for value in values { for value in values {
let decoded = Decodable::decode(&mut decoder); let decoded = Decodable::decode(&mut decoder);
assert_eq!(value, decoded); assert_eq!(value, decoded);
@ -61,7 +65,7 @@ fn test_u8() {
#[test] #[test]
fn test_u16() { fn test_u16() {
for i in u16::MIN..u16::MAX { for i in [u16::MIN, 111, 3333, 55555, u16::MAX] {
check_round_trip(vec![1, 2, 3, i, i, i]); check_round_trip(vec![1, 2, 3, i, i, i]);
} }
} }
@ -92,7 +96,7 @@ fn test_i8() {
#[test] #[test]
fn test_i16() { fn test_i16() {
for i in i16::MIN..i16::MAX { for i in [i16::MIN, -100, 0, 101, i16::MAX] {
check_round_trip(vec![-1, 2, -3, i, i, i, 2]); check_round_trip(vec![-1, 2, -3, i, i, i, 2]);
} }
} }
@ -251,3 +255,41 @@ fn test_tuples() {
check_round_trip(vec![(1234567isize, 100000000000000u64, 99999999999999i64)]); check_round_trip(vec![(1234567isize, 100000000000000u64, 99999999999999i64)]);
check_round_trip(vec![(String::new(), "some string".to_string())]); check_round_trip(vec![(String::new(), "some string".to_string())]);
} }
#[test]
fn test_unit_like_struct() {
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct UnitLikeStruct;
check_round_trip(vec![UnitLikeStruct]);
}
#[test]
fn test_box() {
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct A {
foo: Box<[bool]>,
}
let obj = A { foo: Box::new([true, false]) };
check_round_trip(vec![obj]);
}
#[test]
fn test_cell() {
use std::cell::{Cell, RefCell};
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct A {
baz: isize,
}
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct B {
foo: Cell<bool>,
bar: RefCell<A>,
}
let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
check_round_trip(vec![obj]);
}

View File

@ -1,34 +0,0 @@
// run-pass
#![allow(unused_imports)]
#![feature(rustc_private)]
extern crate rustc_macros;
extern crate rustc_serialize;
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
// files.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
#[derive(Encodable, Decodable)]
struct A {
foo: Box<[bool]>,
}
fn main() {
let obj = A { foo: Box::new([true, false]) };
let mut encoder = MemEncoder::new();
obj.encode(&mut encoder);
let data = encoder.finish();
let mut decoder = MemDecoder::new(&data, 0);
let obj2 = A::decode(&mut decoder);
assert_eq!(obj.foo, obj2.foo);
}

View File

@ -1,44 +0,0 @@
// run-pass
#![allow(unused_imports)]
// This briefly tests the capability of `Cell` and `RefCell` to implement the
// `Encodable` and `Decodable` traits via `#[derive(Encodable, Decodable)]`
#![feature(rustc_private)]
extern crate rustc_macros;
extern crate rustc_serialize;
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
// files.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
use std::cell::{Cell, RefCell};
#[derive(Encodable, Decodable)]
struct A {
baz: isize,
}
#[derive(Encodable, Decodable)]
struct B {
foo: Cell<bool>,
bar: RefCell<A>,
}
fn main() {
let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
let mut encoder = MemEncoder::new();
obj.encode(&mut encoder);
let data = encoder.finish();
let mut decoder = MemDecoder::new(&data, 0);
let obj2 = B::decode(&mut decoder);
assert_eq!(obj.foo.get(), obj2.foo.get());
assert_eq!(obj.bar.borrow().baz, obj2.bar.borrow().baz);
}

View File

@ -1,33 +0,0 @@
// run-pass
#![allow(unused_mut)]
#![allow(unused_imports)]
#![feature(rustc_private)]
extern crate rustc_macros;
extern crate rustc_serialize;
// Necessary to pull in object code as the rest of the rustc crates are shipped only as rmeta
// files.
#[allow(unused_extern_crates)]
extern crate rustc_driver;
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::opaque::{MemDecoder, MemEncoder};
use rustc_serialize::{Decodable, Encodable, Encoder};
#[derive(Encodable, Decodable, PartialEq, Debug)]
struct UnitLikeStruct;
pub fn main() {
let obj = UnitLikeStruct;
let mut encoder = MemEncoder::new();
obj.encode(&mut encoder);
let data = encoder.finish();
let mut decoder = MemDecoder::new(&data, 0);
let obj2 = UnitLikeStruct::decode(&mut decoder);
assert_eq!(obj, obj2);
}