From 62089c335fbdbe2a04c432239dce9e6e8f9a5e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 3 Mar 2018 06:17:06 +0100 Subject: [PATCH] Make metadata references Send + Sync --- src/librustc/middle/cstore.rs | 7 ++- .../owning_ref/mod.rs | 47 ++++++++++++++++--- src/librustc_data_structures/sync.rs | 3 +- src/librustc_llvm/archive_ro.rs | 2 + src/librustc_llvm/lib.rs | 2 + src/librustc_metadata/cstore.rs | 5 +- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/locator.rs | 10 ++-- src/librustc_trans/lib.rs | 2 +- src/librustc_trans/metadata.rs | 12 +++-- src/librustc_trans_utils/lib.rs | 2 +- src/librustc_trans_utils/trans_crate.rs | 14 +++--- 12 files changed, 76 insertions(+), 31 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 7f068e8f71b4b..ea11930ae89d4 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -37,13 +37,12 @@ use util::nodemap::NodeSet; use std::any::Any; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use rustc_data_structures::owning_ref::ErasedBoxRef; use syntax::ast; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos::Span; use rustc_back::target::Target; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{MetadataRef, Lrc}; pub use self::NativeLibraryKind::*; @@ -187,11 +186,11 @@ pub trait MetadataLoader { fn get_rlib_metadata(&self, target: &Target, filename: &Path) - -> Result, String>; + -> Result; fn get_dylib_metadata(&self, target: &Target, filename: &Path) - -> Result, String>; + -> Result; } #[derive(Clone)] diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index 23e0733748b4a..c466b8f8ad1b5 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -243,6 +243,7 @@ fn main() { ``` */ +use std::mem; pub use stable_deref_trait::{StableDeref as StableAddress, CloneStableDeref as CloneStableAddress}; /// An owning reference. @@ -279,7 +280,7 @@ pub struct OwningRefMut { pub trait Erased {} impl Erased for T {} -/// Helper trait for erasing the concrete type of what an owner derferences to, +/// Helper trait for erasing the concrete type of what an owner dereferences to, /// for example `Box -> Box`. This would be unneeded with /// higher kinded types support in the language. pub unsafe trait IntoErased<'a> { @@ -289,10 +290,20 @@ pub unsafe trait IntoErased<'a> { fn into_erased(self) -> Self::Erased; } -/// Helper trait for erasing the concrete type of what an owner derferences to, +/// Helper trait for erasing the concrete type of what an owner dereferences to, +/// for example `Box -> Box`. This would be unneeded with +/// higher kinded types support in the language. +pub unsafe trait IntoErasedSend<'a> { + /// Owner with the dereference type substituted to `Erased + Send`. + type Erased: Send; + /// Perform the type erasure. + fn into_erased_send(self) -> Self::Erased; +} + +/// Helper trait for erasing the concrete type of what an owner dereferences to, /// for example `Box -> Box`. This would be unneeded with /// higher kinded types support in the language. -pub unsafe trait IntoErasedSendSync<'a>: Send + Sync { +pub unsafe trait IntoErasedSendSync<'a> { /// Owner with the dereference type substituted to `Erased + Send + Sync`. type Erased: Send + Sync; /// Perform the type erasure. @@ -472,6 +483,18 @@ impl OwningRef { } } + /// Erases the concrete base type of the owner with a trait object which implements `Send`. + /// + /// This allows mixing of owned references with different owner base types. + pub fn erase_send_owner<'a>(self) -> OwningRef + where O: IntoErasedSend<'a>, + { + OwningRef { + reference: self.reference, + owner: self.owner.into_erased_send(), + } + } + /// Erases the concrete base type of the owner with a trait object which implements `Send` and `Sync`. /// /// This allows mixing of owned references with different owner base types. @@ -1161,13 +1184,25 @@ unsafe impl<'a, T: 'a> IntoErased<'a> for Arc { } } -unsafe impl<'a, T: Send + Sync + 'a> IntoErasedSendSync<'a> for Box { - type Erased = Box; - fn into_erased_send_sync(self) -> Self::Erased { +unsafe impl<'a, T: Send + 'a> IntoErasedSend<'a> for Box { + type Erased = Box; + fn into_erased_send(self) -> Self::Erased { self } } +unsafe impl<'a, T: Send + 'a> IntoErasedSendSync<'a> for Box { + type Erased = Box; + fn into_erased_send_sync(self) -> Self::Erased { + let result: Box = self; + // This is safe since Erased can always implement Sync + // Only the destructor is available and it takes &mut self + unsafe { + mem::transmute(result) + } + } +} + unsafe impl<'a, T: Send + Sync + 'a> IntoErasedSendSync<'a> for Arc { type Erased = Arc; fn into_erased_send_sync(self) -> Self::Erased { diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index b1ab4eaa06924..69fc9ef785eb7 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -177,7 +177,7 @@ cfg_if! { macro_rules! rustc_erase_owner { ($v:expr) => {{ let v = $v; - ::rustc_data_structures::sync::assert_send_sync_val(&v); + ::rustc_data_structures::sync::assert_send_val(&v); v.erase_send_sync_owner() }} } @@ -262,6 +262,7 @@ cfg_if! { } pub fn assert_sync() {} +pub fn assert_send_val(_t: &T) {} pub fn assert_send_sync_val(_t: &T) {} #[macro_export] diff --git a/src/librustc_llvm/archive_ro.rs b/src/librustc_llvm/archive_ro.rs index 6c3626cd880b2..9d8690072709b 100644 --- a/src/librustc_llvm/archive_ro.rs +++ b/src/librustc_llvm/archive_ro.rs @@ -22,6 +22,8 @@ pub struct ArchiveRO { ptr: ArchiveRef, } +unsafe impl Send for ArchiveRO {} + pub struct Iter<'a> { archive: &'a ArchiveRO, ptr: ::ArchiveIteratorRef, diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 8dcf7444dd18f..16bee5b987e2d 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -221,6 +221,8 @@ pub struct ObjectFile { pub llof: ObjectFileRef, } +unsafe impl Send for ObjectFile {} + impl ObjectFile { // This will take ownership of llmb pub fn new(llmb: MemoryBufferRef) -> Option { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 8b59eec019050..d5a1771d5353e 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -24,7 +24,6 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet, NodeMap}; use std::cell::{RefCell, Cell}; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::owning_ref::ErasedBoxRef; use syntax::{ast, attr}; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; @@ -42,7 +41,9 @@ pub use cstore_impl::{provide, provide_extern}; // own crate numbers. pub type CrateNumMap = IndexVec; -pub struct MetadataBlob(pub ErasedBoxRef<[u8]>); +pub use rustc_data_structures::sync::MetadataRef; + +pub struct MetadataBlob(pub MetadataRef); /// Holds information about a syntax_pos::FileMap imported from another crate. /// See `imported_filemaps()` for more information. diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 2d015fa81f925..da0da622d5214 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -39,6 +39,7 @@ extern crate proc_macro; #[macro_use] extern crate rustc; extern crate rustc_back; +#[macro_use] extern crate rustc_data_structures; mod diagnostics; diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index e0fb924f1aa3e..c56674bd6c5a9 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -219,7 +219,7 @@ //! no means all of the necessary details. Take a look at the rest of //! metadata::locator or metadata::creader for all the juicy details! -use cstore::MetadataBlob; +use cstore::{MetadataRef, MetadataBlob}; use creader::Library; use schema::{METADATA_HEADER, rustc_version}; @@ -243,8 +243,8 @@ use std::path::{Path, PathBuf}; use std::time::Instant; use flate2::read::DeflateDecoder; -use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef}; +use rustc_data_structures::owning_ref::OwningRef; pub struct CrateMismatch { path: PathBuf, got: String, @@ -842,7 +842,7 @@ fn get_metadata_section_imp(target: &Target, if !filename.exists() { return Err(format!("no such file: '{}'", filename.display())); } - let raw_bytes: ErasedBoxRef<[u8]> = match flavor { + let raw_bytes: MetadataRef = match flavor { CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?, CrateFlavor::Dylib => { let buf = loader.get_dylib_metadata(target, filename)?; @@ -862,7 +862,7 @@ fn get_metadata_section_imp(target: &Target, match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => { let buf = unsafe { OwningRef::new_assert_stable_address(inflated) }; - buf.map_owner_box().erase_owner() + rustc_erase_owner!(buf.map_owner_box()) } Err(_) => { return Err(format!("failed to decompress metadata: {}", filename.display())); @@ -872,7 +872,7 @@ fn get_metadata_section_imp(target: &Target, CrateFlavor::Rmeta => { let buf = fs::read(filename).map_err(|_| format!("failed to read rmeta metadata: '{}'", filename.display()))?; - OwningRef::new(buf).map_owner_box().erase_owner() + rustc_erase_owner!(OwningRef::new(buf).map_owner_box()) } }; let blob = MetadataBlob(raw_bytes); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6cb9d2027c747..960e2ed629a13 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -51,7 +51,7 @@ extern crate rustc_apfloat; extern crate rustc_back; extern crate rustc_binaryen; extern crate rustc_const_math; -extern crate rustc_data_structures; +#[macro_use] extern crate rustc_data_structures; extern crate rustc_demangle; extern crate rustc_incremental; extern crate rustc_llvm as llvm; diff --git a/src/librustc_trans/metadata.rs b/src/librustc_trans/metadata.rs index d57624da0c68d..9483420f2f0e7 100644 --- a/src/librustc_trans/metadata.rs +++ b/src/librustc_trans/metadata.rs @@ -15,17 +15,19 @@ use llvm; use llvm::{False, ObjectFile, mk_section_iter}; use llvm::archive_ro::ArchiveRO; -use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef}; +use rustc_data_structures::owning_ref::OwningRef; use std::path::Path; use std::ptr; use std::slice; +pub use rustc_data_structures::sync::MetadataRef; + pub const METADATA_FILENAME: &str = "rust.metadata.bin"; pub struct LlvmMetadataLoader; impl MetadataLoader for LlvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap // internally to read the file. We also avoid even using a memcpy by // just keeping the archive along while the metadata is in use. @@ -47,13 +49,13 @@ impl MetadataLoader for LlvmMetadataLoader { filename.display()) }) })?; - Ok(buf.erase_owner()) + Ok(rustc_erase_owner!(buf)) } fn get_dylib_metadata(&self, target: &Target, filename: &Path) - -> Result, String> { + -> Result { unsafe { let buf = common::path2cstr(filename); let mb = llvm::LLVMRustCreateMemoryBufferWithContentsOfFile(buf.as_ptr()); @@ -65,7 +67,7 @@ impl MetadataLoader for LlvmMetadataLoader { .ok_or_else(|| format!("provided path not an object file: '{}'", filename.display()))?; let buf = of.try_map(|of| search_meta_section(of, target, filename))?; - Ok(buf.erase_owner()) + Ok(rustc_erase_owner!(buf)) } } } diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index bfecb20198366..e87ab3abdf8ed 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -40,7 +40,7 @@ extern crate rustc_incremental; #[macro_use] extern crate syntax; extern crate syntax_pos; -extern crate rustc_data_structures; +#[macro_use] extern crate rustc_data_structures; pub extern crate rustc as __rustc; diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 419371ba3e339..1e896f261c03e 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -28,7 +28,7 @@ use std::fs::File; use std::path::Path; use std::sync::mpsc; -use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef}; +use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::sync::Lrc; use ar::{Archive, Builder, Header}; use flate2::Compression; @@ -47,6 +47,8 @@ use rustc_back::target::Target; use rustc_mir::monomorphize::collector; use link::{build_link_meta, out_filename}; +pub use rustc_data_structures::sync::MetadataRef; + pub trait TransCrate { fn init(&self, _sess: &Session) {} fn print(&self, _req: PrintRequest, _sess: &Session) {} @@ -119,7 +121,7 @@ impl MetadataLoader for DummyMetadataLoader { &self, _target: &Target, _filename: &Path - ) -> Result, String> { + ) -> Result { bug!("DummyMetadataLoader::get_rlib_metadata"); } @@ -127,7 +129,7 @@ impl MetadataLoader for DummyMetadataLoader { &self, _target: &Target, _filename: &Path - ) -> Result, String> { + ) -> Result { bug!("DummyMetadataLoader::get_dylib_metadata"); } } @@ -135,7 +137,7 @@ impl MetadataLoader for DummyMetadataLoader { pub struct NoLlvmMetadataLoader; impl MetadataLoader for NoLlvmMetadataLoader { - fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result, String> { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { let file = File::open(filename) .map_err(|e| format!("metadata file open err: {:?}", e))?; let mut archive = Archive::new(file); @@ -147,7 +149,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { let mut buf = Vec::new(); io::copy(&mut entry, &mut buf).unwrap(); let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); - return Ok(buf.map_owner_box().erase_owner()); + return Ok(rustc_erase_owner!(buf.map_owner_box())); } } @@ -158,7 +160,7 @@ impl MetadataLoader for NoLlvmMetadataLoader { &self, _target: &Target, _filename: &Path, - ) -> Result, String> { + ) -> Result { // FIXME: Support reading dylibs from llvm enabled rustc self.get_rlib_metadata(_target, _filename) }