Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0f0dc29

Browse files
committedApr 8, 2023
Auto merge of #109971 - WaffleLapkin:yeet_ownership, r=Nilstrieb
Yeet `owning_ref` Based on the discussions from #109948 This replaces `owning_ref` with a far simpler & safer abstraction. Fixes #109974
2 parents ba86600 + fbe0591 commit 0f0dc29

File tree

13 files changed

+227
-2012
lines changed

13 files changed

+227
-2012
lines changed
 

‎compiler/rustc_codegen_ssa/src/back/metadata.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use object::{
1313
use snap::write::FrameEncoder;
1414

1515
use rustc_data_structures::memmap::Mmap;
16-
use rustc_data_structures::owning_ref::OwningRef;
17-
use rustc_data_structures::rustc_erase_owner;
16+
use rustc_data_structures::owned_slice::try_slice_owned;
1817
use rustc_data_structures::sync::MetadataRef;
1918
use rustc_metadata::fs::METADATA_FILENAME;
2019
use rustc_metadata::EncodedMetadata;
@@ -42,10 +41,10 @@ fn load_metadata_with(
4241
) -> Result<MetadataRef, String> {
4342
let file =
4443
File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
45-
let data = unsafe { Mmap::map(file) }
46-
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))?;
47-
let metadata = OwningRef::new(data).try_map(f)?;
48-
return Ok(rustc_erase_owner!(metadata.map_owner_box()));
44+
45+
unsafe { Mmap::map(file) }
46+
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))
47+
.and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap)))
4948
}
5049

5150
impl MetadataLoader for DefaultMetadataLoader {

‎compiler/rustc_data_structures/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Various data structures used by the Rust compiler. The intention
2-
//! is that code in here should be not be *specific* to rustc, so that
2+
//! is that code in here should not be *specific* to rustc, so that
33
//! it can be easily unit tested and so forth.
44
//!
55
//! # Note
@@ -27,6 +27,8 @@
2727
#![feature(thread_id_value)]
2828
#![feature(vec_into_raw_parts)]
2929
#![feature(get_mut_unchecked)]
30+
#![feature(lint_reasons)]
31+
#![feature(unwrap_infallible)]
3032
#![allow(rustc::default_hash_types)]
3133
#![allow(rustc::potential_query_instability)]
3234
#![deny(rustc::untranslatable_diagnostic)]
@@ -59,7 +61,6 @@ pub mod intern;
5961
pub mod jobserver;
6062
pub mod macros;
6163
pub mod obligation_forest;
62-
pub mod owning_ref;
6364
pub mod sip128;
6465
pub mod small_c_str;
6566
pub mod small_str;
@@ -82,6 +83,7 @@ pub mod vec_linked_list;
8283
pub mod work_queue;
8384
pub use atomic_ref::AtomicRef;
8485
pub mod frozen;
86+
pub mod owned_slice;
8587
pub mod sso;
8688
pub mod steal;
8789
pub mod tagged_ptr;

‎compiler/rustc_data_structures/src/memmap.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ use std::fs::File;
22
use std::io;
33
use std::ops::{Deref, DerefMut};
44

5-
use crate::owning_ref::StableAddress;
6-
7-
/// A trivial wrapper for [`memmap2::Mmap`] that implements [`StableAddress`].
5+
/// A trivial wrapper for [`memmap2::Mmap`] (or `Vec<u8>` on WASM).
86
#[cfg(not(target_arch = "wasm32"))]
97
pub struct Mmap(memmap2::Mmap);
108

@@ -46,12 +44,6 @@ impl AsRef<[u8]> for Mmap {
4644
}
4745
}
4846

49-
// SAFETY: On architectures other than WASM, mmap is used as backing storage. The address of this
50-
// memory map is stable. On WASM, `Vec<u8>` is used as backing storage. The `Mmap` type doesn't
51-
// export any function that can cause the `Vec` to be re-allocated. As such the address of the
52-
// bytes inside this `Vec` is stable.
53-
unsafe impl StableAddress for Mmap {}
54-
5547
#[cfg(not(target_arch = "wasm32"))]
5648
pub struct MmapMut(memmap2::MmapMut);
5749

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use std::{borrow::Borrow, ops::Deref};
2+
3+
// Use our fake Send/Sync traits when on not parallel compiler,
4+
// so that `OwnedSlice` only implements/requires Send/Sync
5+
// for parallel compiler builds.
6+
use crate::sync::{Send, Sync};
7+
8+
/// An owned slice.
9+
///
10+
/// This is similar to `Box<[u8]>` but allows slicing and using anything as the
11+
/// backing buffer.
12+
///
13+
/// See [`slice_owned`] for `OwnedSlice` construction and examples.
14+
///
15+
/// ---------------------------------------------------------------------------
16+
///
17+
/// This is essentially a replacement for `owning_ref` which is a lot simpler
18+
/// and even sound! 🌸
19+
pub struct OwnedSlice {
20+
/// This is conceptually a `&'self.owner [u8]`.
21+
bytes: *const [u8],
22+
23+
// +---------------------------------------+
24+
// | We expect `dead_code` lint here, |
25+
// | because we don't want to accidentally |
26+
// | touch the owner — otherwise the owner |
27+
// | could invalidate out `bytes` pointer |
28+
// | |
29+
// | so be quiet |
30+
// +----+ +-------------------------------+
31+
// \/
32+
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
33+
#[expect(dead_code)]
34+
owner: Box<dyn Send + Sync>,
35+
}
36+
37+
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
38+
///
39+
/// ## Examples
40+
///
41+
/// ```rust
42+
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
43+
/// let vec = vec![1, 2, 3, 4];
44+
///
45+
/// // Identical to slicing via `&v[1..3]` but produces an owned slice
46+
/// let slice: OwnedSlice = slice_owned(vec, |v| &v[1..3]);
47+
/// assert_eq!(&*slice, [2, 3]);
48+
/// ```
49+
///
50+
/// ```rust
51+
/// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
52+
/// # use std::ops::Deref;
53+
/// let vec = vec![1, 2, 3, 4];
54+
///
55+
/// // Identical to slicing via `&v[..]` but produces an owned slice
56+
/// let slice: OwnedSlice = slice_owned(vec, Deref::deref);
57+
/// assert_eq!(&*slice, [1, 2, 3, 4]);
58+
/// ```
59+
pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
60+
where
61+
O: Send + Sync + 'static,
62+
F: FnOnce(&O) -> &[u8],
63+
{
64+
try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
65+
}
66+
67+
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function that can fail.
68+
///
69+
/// See [`slice_owned`] for the infallible version.
70+
pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
71+
where
72+
O: Send + Sync + 'static,
73+
F: FnOnce(&O) -> Result<&[u8], E>,
74+
{
75+
// We box the owner of the bytes, so it doesn't move.
76+
//
77+
// Since the owner does not move and we don't access it in any way
78+
// before drop, there is nothing that can invalidate the bytes pointer.
79+
//
80+
// Thus, "extending" the lifetime of the reference returned from `F` is fine.
81+
// We pretend that we pass it a reference that lives as long as the returned slice.
82+
//
83+
// N.B. the HRTB on the `slicer` is important — without it the caller could provide
84+
// a short lived slice, unrelated to the owner.
85+
86+
let owner = Box::new(owner);
87+
let bytes = slicer(&*owner)?;
88+
89+
Ok(OwnedSlice { bytes, owner })
90+
}
91+
92+
impl Deref for OwnedSlice {
93+
type Target = [u8];
94+
95+
#[inline]
96+
fn deref(&self) -> &[u8] {
97+
// Safety:
98+
// `self.bytes` is valid per the construction in `slice_owned`
99+
// (which is the only constructor)
100+
unsafe { &*self.bytes }
101+
}
102+
}
103+
104+
impl Borrow<[u8]> for OwnedSlice {
105+
#[inline]
106+
fn borrow(&self) -> &[u8] {
107+
self
108+
}
109+
}
110+
111+
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
112+
unsafe impl Send for OwnedSlice {}
113+
114+
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
115+
unsafe impl Sync for OwnedSlice {}
116+
117+
#[cfg(test)]
118+
mod tests;
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use std::{
2+
ops::Deref,
3+
sync::{
4+
atomic::{self, AtomicBool},
5+
Arc,
6+
},
7+
};
8+
9+
use crate::{
10+
owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
11+
OnDrop,
12+
};
13+
14+
#[test]
15+
fn smoke() {
16+
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
17+
18+
assert_eq!(&*slice, [1, 2, 3, 4, 5, 6]);
19+
}
20+
21+
#[test]
22+
fn static_storage() {
23+
let slice = slice_owned(Box::new(String::from("what")), |_| b"bytes boo");
24+
25+
assert_eq!(&*slice, b"bytes boo");
26+
}
27+
28+
#[test]
29+
fn slice_the_slice() {
30+
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
31+
let slice = slice_owned(slice, |s| &s[1..][..4]);
32+
let slice = slice_owned(slice, |s| s);
33+
let slice = slice_owned(slice, |s| &s[1..]);
34+
35+
assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]);
36+
}
37+
38+
#[test]
39+
fn try_and_fail() {
40+
let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(()));
41+
42+
assert!(res.is_err());
43+
}
44+
45+
#[test]
46+
fn boxed() {
47+
// It's important that we don't cause UB because of `Box`'es uniqueness
48+
49+
let boxed: Box<[u8]> = vec![1, 1, 2, 3, 5, 8, 13, 21].into_boxed_slice();
50+
let slice = slice_owned(boxed, Deref::deref);
51+
52+
assert_eq!(&*slice, [1, 1, 2, 3, 5, 8, 13, 21]);
53+
}
54+
55+
#[test]
56+
fn drop_drops() {
57+
let flag = Arc::new(AtomicBool::new(false));
58+
let flag_prime = Arc::clone(&flag);
59+
let d = OnDrop(move || flag_prime.store(true, atomic::Ordering::Relaxed));
60+
61+
let slice = slice_owned(d, |_| &[]);
62+
63+
assert_eq!(flag.load(atomic::Ordering::Relaxed), false);
64+
65+
drop(slice);
66+
67+
assert_eq!(flag.load(atomic::Ordering::Relaxed), true);
68+
}
69+
70+
#[test]
71+
fn send_sync() {
72+
crate::sync::assert_send::<OwnedSlice>();
73+
crate::sync::assert_sync::<OwnedSlice>();
74+
}

‎compiler/rustc_data_structures/src/owning_ref/LICENSE

Lines changed: 0 additions & 21 deletions
This file was deleted.

‎compiler/rustc_data_structures/src/owning_ref/mod.rs

Lines changed: 0 additions & 1211 deletions
This file was deleted.

‎compiler/rustc_data_structures/src/owning_ref/tests.rs

Lines changed: 0 additions & 711 deletions
This file was deleted.

‎compiler/rustc_data_structures/src/sync.rs

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
//! while the serial versions degenerate straightforwardly to serial execution.
88
//! The operations include `join`, `parallel`, `par_iter`, and `par_for_each`.
99
//!
10-
//! `rustc_erase_owner!` erases an `OwningRef` owner into `Erased` for the
11-
//! serial version and `Erased + Send + Sync` for the parallel version.
12-
//!
1310
//! Types
1411
//! -----
1512
//! The parallel versions of types provide various kinds of synchronization,
@@ -42,7 +39,7 @@
4239
//!
4340
//! [^2] `MTLockRef` is a typedef.
4441
45-
use crate::owning_ref::{Erased, OwningRef};
42+
use crate::owned_slice::OwnedSlice;
4643
use std::collections::HashMap;
4744
use std::hash::{BuildHasher, Hash};
4845
use std::ops::{Deref, DerefMut};
@@ -57,18 +54,11 @@ mod vec;
5754

5855
cfg_if! {
5956
if #[cfg(not(parallel_compiler))] {
60-
pub auto trait Send {}
61-
pub auto trait Sync {}
62-
63-
impl<T> Send for T {}
64-
impl<T> Sync for T {}
57+
pub unsafe auto trait Send {}
58+
pub unsafe auto trait Sync {}
6559

66-
#[macro_export]
67-
macro_rules! rustc_erase_owner {
68-
($v:expr) => {
69-
$v.erase_owner()
70-
}
71-
}
60+
unsafe impl<T> Send for T {}
61+
unsafe impl<T> Sync for T {}
7262

7363
use std::ops::Add;
7464

@@ -197,7 +187,7 @@ cfg_if! {
197187
}
198188
}
199189

200-
pub type MetadataRef = OwningRef<Box<dyn Erased>, [u8]>;
190+
pub type MetadataRef = OwnedSlice;
201191

202192
pub use std::rc::Rc as Lrc;
203193
pub use std::rc::Weak as Weak;
@@ -380,20 +370,11 @@ cfg_if! {
380370
});
381371
}
382372

383-
pub type MetadataRef = OwningRef<Box<dyn Erased + Send + Sync>, [u8]>;
373+
pub type MetadataRef = OwnedSlice;
384374

385375
/// This makes locks panic if they are already held.
386376
/// It is only useful when you are running in a single thread
387377
const ERROR_CHECKING: bool = false;
388-
389-
#[macro_export]
390-
macro_rules! rustc_erase_owner {
391-
($v:expr) => {{
392-
let v = $v;
393-
::rustc_data_structures::sync::assert_send_val(&v);
394-
v.erase_send_sync_owner()
395-
}}
396-
}
397378
}
398379
}
399380

‎compiler/rustc_metadata/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ extern crate proc_macro;
2222
extern crate rustc_macros;
2323
#[macro_use]
2424
extern crate rustc_middle;
25-
#[macro_use]
26-
extern crate rustc_data_structures;
2725

2826
#[macro_use]
2927
extern crate tracing;

‎compiler/rustc_metadata/src/locator.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER};
218218

219219
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
220220
use rustc_data_structures::memmap::Mmap;
221-
use rustc_data_structures::owning_ref::OwningRef;
221+
use rustc_data_structures::owned_slice::slice_owned;
222222
use rustc_data_structures::svh::Svh;
223223
use rustc_data_structures::sync::MetadataRef;
224224
use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
@@ -236,6 +236,7 @@ use rustc_target::spec::{Target, TargetTriple};
236236
use snap::read::FrameDecoder;
237237
use std::borrow::Cow;
238238
use std::io::{Read, Result as IoResult, Write};
239+
use std::ops::Deref;
239240
use std::path::{Path, PathBuf};
240241
use std::{cmp, fmt};
241242

@@ -814,15 +815,14 @@ fn get_metadata_section<'p>(
814815
// Assume the decompressed data will be at least the size of the compressed data, so we
815816
// don't have to grow the buffer as much.
816817
let mut inflated = Vec::with_capacity(compressed_bytes.len());
817-
match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
818-
Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()),
819-
Err(_) => {
820-
return Err(MetadataError::LoadFailure(format!(
821-
"failed to decompress metadata: {}",
822-
filename.display()
823-
)));
824-
}
825-
}
818+
FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated).map_err(|_| {
819+
MetadataError::LoadFailure(format!(
820+
"failed to decompress metadata: {}",
821+
filename.display()
822+
))
823+
})?;
824+
825+
slice_owned(inflated, Deref::deref)
826826
}
827827
CrateFlavor::Rmeta => {
828828
// mmap the file, because only a small fraction of it is read.
@@ -840,7 +840,7 @@ fn get_metadata_section<'p>(
840840
))
841841
})?;
842842

843-
rustc_erase_owner!(OwningRef::new(mmap).map_owner_box())
843+
slice_owned(mmap, Deref::deref)
844844
}
845845
};
846846
let blob = MetadataBlob::new(raw_bytes);

‎compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,6 @@ mod cstore_impl;
5151
#[derive(Clone)]
5252
pub(crate) struct MetadataBlob(Lrc<MetadataRef>);
5353

54-
// This is needed so we can create an OwningRef into the blob.
55-
// The data behind a `MetadataBlob` has a stable address because it is
56-
// contained within an Rc/Arc.
57-
unsafe impl rustc_data_structures::owning_ref::StableAddress for MetadataBlob {}
58-
59-
// This is needed so we can create an OwningRef into the blob.
6054
impl std::ops::Deref for MetadataBlob {
6155
type Target = [u8];
6256

‎compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use crate::rmeta::DecodeContext;
22
use crate::rmeta::EncodeContext;
3-
use crate::rmeta::MetadataBlob;
4-
use rustc_data_structures::owning_ref::OwningRef;
3+
use rustc_data_structures::owned_slice::slice_owned;
4+
use rustc_data_structures::owned_slice::OwnedSlice;
55
use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
66
use rustc_middle::parameterized_over_tcx;
77
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
88
use rustc_span::def_id::{DefIndex, DefPathHash};
99

1010
pub(crate) enum DefPathHashMapRef<'tcx> {
11-
OwnedFromMetadata(odht::HashTable<HashMapConfig, OwningRef<MetadataBlob, [u8]>>),
11+
OwnedFromMetadata(odht::HashTable<HashMapConfig, OwnedSlice>),
1212
BorrowedFromTcx(&'tcx DefPathHashMap),
1313
}
1414

@@ -50,11 +50,11 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static>
5050

5151
let len = d.read_usize();
5252
let pos = d.position();
53-
let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]);
53+
let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]);
5454

55-
// Although we already have the data we need via the OwningRef, we still need
56-
// to advance the DecodeContext's position so it's in a valid state after
57-
// the method. We use read_raw_bytes() for that.
55+
// Although we already have the data we need via the `OwnedSlice`, we still need
56+
// to advance the `DecodeContext`'s position so it's in a valid state after
57+
// the method. We use `read_raw_bytes()` for that.
5858
let _ = d.read_raw_bytes(len);
5959

6060
let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| {

0 commit comments

Comments
 (0)
Please sign in to comment.