Skip to content

Commit 0ced530

Browse files
committed
Auto merge of #83465 - michaelwoerister:safe-read_raw_bytes, r=cjgillot
Allow for reading raw bytes from rustc_serialize::Decoder without unsafe code The current `read_raw_bytes` method requires using `MaybeUninit` and `unsafe`. I don't think this is necessary. Let's see if a safe interface has any performance drawbacks. This is a followup to #83273 and will make it easier to rebase #82183. r? `@cjgillot`
2 parents 3debe9a + 517d5ac commit 0ced530

File tree

5 files changed

+48
-45
lines changed

5 files changed

+48
-45
lines changed

compiler/rustc_data_structures/src/fingerprint.rs

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::stable_hasher;
22
use rustc_serialize::{Decodable, Encodable};
3+
use std::convert::TryInto;
34
use std::hash::{Hash, Hasher};
4-
use std::mem::{self, MaybeUninit};
55

66
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
77
#[repr(C)]
@@ -60,6 +60,29 @@ impl Fingerprint {
6060
pub fn to_hex(&self) -> String {
6161
format!("{:x}{:x}", self.0, self.1)
6262
}
63+
64+
#[inline]
65+
pub fn to_le_bytes(&self) -> [u8; 16] {
66+
// This seems to optimize to the same machine code as
67+
// `unsafe { mem::transmute(*k) }`. Well done, LLVM! :)
68+
let mut result = [0u8; 16];
69+
70+
let first_half: &mut [u8; 8] = (&mut result[0..8]).try_into().unwrap();
71+
*first_half = self.0.to_le_bytes();
72+
73+
let second_half: &mut [u8; 8] = (&mut result[8..16]).try_into().unwrap();
74+
*second_half = self.1.to_le_bytes();
75+
76+
result
77+
}
78+
79+
#[inline]
80+
pub fn from_le_bytes(bytes: [u8; 16]) -> Fingerprint {
81+
Fingerprint(
82+
u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
83+
u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
84+
)
85+
}
6386
}
6487

6588
impl std::fmt::Display for Fingerprint {
@@ -119,20 +142,17 @@ impl_stable_hash_via_hash!(Fingerprint);
119142
impl<E: rustc_serialize::Encoder> Encodable<E> for Fingerprint {
120143
#[inline]
121144
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
122-
let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) };
123-
s.emit_raw_bytes(&bytes)?;
145+
s.emit_raw_bytes(&self.to_le_bytes()[..])?;
124146
Ok(())
125147
}
126148
}
127149

128150
impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint {
129151
#[inline]
130152
fn decode(d: &mut D) -> Result<Self, D::Error> {
131-
let mut bytes: [MaybeUninit<u8>; 16] = MaybeUninit::uninit_array();
132-
d.read_raw_bytes(&mut bytes)?;
133-
134-
let [l, r]: [u64; 2] = unsafe { mem::transmute(bytes) };
135-
Ok(Fingerprint(u64::from_le(l), u64::from_le(r)))
153+
let mut bytes = [0u8; 16];
154+
d.read_raw_bytes_into(&mut bytes[..])?;
155+
Ok(Fingerprint::from_le_bytes(bytes))
136156
}
137157
}
138158

compiler/rustc_middle/src/ty/codec.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,8 @@ macro_rules! implement_ty_decoder {
473473
}
474474

475475
#[inline]
476-
fn read_raw_bytes(&mut self, bytes: &mut [std::mem::MaybeUninit<u8>]) -> Result<(), Self::Error> {
477-
self.opaque.read_raw_bytes(bytes)
476+
fn read_raw_bytes_into(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> {
477+
self.opaque.read_raw_bytes_into(bytes)
478478
}
479479

480480
fn error(&mut self, err: &str) -> Self::Error {

compiler/rustc_serialize/src/json.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ use std::collections::{BTreeMap, HashMap};
188188
use std::io;
189189
use std::io::prelude::*;
190190
use std::mem::swap;
191-
use std::mem::MaybeUninit;
192191
use std::num::FpCategory as Fp;
193192
use std::ops::Index;
194193
use std::str::FromStr;
@@ -2367,10 +2366,9 @@ impl crate::Decoder for Decoder {
23672366
expect!(self.pop(), String).map(Cow::Owned)
23682367
}
23692368

2370-
fn read_raw_bytes(&mut self, s: &mut [MaybeUninit<u8>]) -> Result<(), Self::Error> {
2369+
fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error> {
23712370
for c in s.iter_mut() {
2372-
let h = self.read_u8()?;
2373-
unsafe { *c.as_mut_ptr() = h };
2371+
*c = self.read_u8()?;
23742372
}
23752373
Ok(())
23762374
}

compiler/rustc_serialize/src/opaque.rs

+15-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::leb128::{self, max_leb128_len};
2-
use crate::serialize::{self, Decoder as _, Encoder as _};
2+
use crate::serialize::{self, Encoder as _};
33
use std::borrow::Cow;
4+
use std::convert::TryInto;
45
use std::fs::File;
56
use std::io::{self, Write};
67
use std::mem::MaybeUninit;
@@ -539,6 +540,13 @@ impl<'a> Decoder<'a> {
539540
pub fn advance(&mut self, bytes: usize) {
540541
self.position += bytes;
541542
}
543+
544+
#[inline]
545+
pub fn read_raw_bytes(&mut self, bytes: usize) -> &'a [u8] {
546+
let start = self.position;
547+
self.position += bytes;
548+
&self.data[start..self.position]
549+
}
542550
}
543551

544552
macro_rules! read_leb128 {
@@ -659,22 +667,10 @@ impl<'a> serialize::Decoder for Decoder<'a> {
659667
}
660668

661669
#[inline]
662-
fn read_raw_bytes(&mut self, s: &mut [MaybeUninit<u8>]) -> Result<(), String> {
670+
fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), String> {
663671
let start = self.position;
664-
let end = start + s.len();
665-
assert!(end <= self.data.len());
666-
667-
// SAFETY: Both `src` and `dst` point to at least `s.len()` elements:
668-
// `src` points to at least `s.len()` elements by above assert, and
669-
// `dst` points to `s.len()` elements by derivation from `s`.
670-
unsafe {
671-
let src = self.data.as_ptr().add(start);
672-
let dst = s.as_mut_ptr() as *mut u8;
673-
ptr::copy_nonoverlapping(src, dst, s.len());
674-
}
675-
676-
self.position = end;
677-
672+
self.position += s.len();
673+
s.copy_from_slice(&self.data[start..self.position]);
678674
Ok(())
679675
}
680676
}
@@ -705,16 +701,7 @@ impl serialize::Encodable<FileEncoder> for [u8] {
705701
impl<'a> serialize::Decodable<Decoder<'a>> for Vec<u8> {
706702
fn decode(d: &mut Decoder<'a>) -> Result<Self, String> {
707703
let len = serialize::Decoder::read_usize(d)?;
708-
709-
let mut v = Vec::with_capacity(len);
710-
let buf = &mut v.spare_capacity_mut()[..len];
711-
d.read_raw_bytes(buf)?;
712-
713-
unsafe {
714-
v.set_len(len);
715-
}
716-
717-
Ok(v)
704+
Ok(d.read_raw_bytes(len).to_owned())
718705
}
719706
}
720707

@@ -750,13 +737,12 @@ impl serialize::Encodable<FileEncoder> for IntEncodedWithFixedSize {
750737
impl<'a> serialize::Decodable<Decoder<'a>> for IntEncodedWithFixedSize {
751738
#[inline]
752739
fn decode(decoder: &mut Decoder<'a>) -> Result<IntEncodedWithFixedSize, String> {
753-
let mut bytes = MaybeUninit::uninit_array();
754740
let _start_pos = decoder.position();
755-
decoder.read_raw_bytes(&mut bytes)?;
741+
let bytes = decoder.read_raw_bytes(IntEncodedWithFixedSize::ENCODED_SIZE);
756742
let _end_pos = decoder.position();
757743
debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
758744

759-
let value = u64::from_le_bytes(unsafe { MaybeUninit::array_assume_init(bytes) });
745+
let value = u64::from_le_bytes(bytes.try_into().unwrap());
760746
Ok(IntEncodedWithFixedSize(value))
761747
}
762748
}

compiler/rustc_serialize/src/serialize.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ Core encoding and decoding interfaces.
77
use std::borrow::Cow;
88
use std::cell::{Cell, RefCell};
99
use std::marker::PhantomData;
10-
use std::mem::MaybeUninit;
1110
use std::path;
1211
use std::rc::Rc;
1312
use std::sync::Arc;
@@ -226,7 +225,7 @@ pub trait Decoder {
226225
fn read_f32(&mut self) -> Result<f32, Self::Error>;
227226
fn read_char(&mut self) -> Result<char, Self::Error>;
228227
fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error>;
229-
fn read_raw_bytes(&mut self, s: &mut [MaybeUninit<u8>]) -> Result<(), Self::Error>;
228+
fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error>;
230229

231230
// Compound types:
232231
#[inline]

0 commit comments

Comments
 (0)