From 2f670664638e24ba6f8d6e33159fe18537e79ba4 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 19 Jun 2024 19:47:42 +0200 Subject: [PATCH 1/2] Add `MaybeLazy`(Cow) for 3-way lazy-ness --- compiler/rustc_target/src/lib.rs | 2 + compiler/rustc_target/src/spec/maybe_lazy.rs | 144 +++++++++++++++++++ compiler/rustc_target/src/spec/mod.rs | 2 + 3 files changed, 148 insertions(+) create mode 100644 compiler/rustc_target/src/spec/maybe_lazy.rs diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index ecc91ab9a310e..2962b0ab61e7f 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -12,11 +12,13 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] +#![feature(fn_traits)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(min_exhaustive_patterns)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(unboxed_closures)] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/maybe_lazy.rs b/compiler/rustc_target/src/spec/maybe_lazy.rs new file mode 100644 index 0000000000000..3694679b01f1c --- /dev/null +++ b/compiler/rustc_target/src/spec/maybe_lazy.rs @@ -0,0 +1,144 @@ +//! A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data. + +use std::borrow::{Borrow, Cow}; +use std::fmt::{Debug, Display}; +use std::ops::Deref; +use std::sync::LazyLock; + +enum MaybeLazyInner { + Lazy(LazyLock), + Cow(Cow<'static, T>), +} + +/// A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data. +/// +/// Technically this structure has 3 states: borrowed, owned and lazy +/// They can all be constructed from the [`MaybeLazy::borrowed`], [`MaybeLazy::owned`] and +/// [`MaybeLazy::lazy`] methods. +#[repr(transparent)] +pub struct MaybeLazy ::Owned> { + // Inner state. + // + // Not to be inlined since we may want in the future to + // make this struct usable to statics and we might need to + // workaround const-eval limitation (particulary around drop). + inner: MaybeLazyInner, +} + +impl T::Owned> MaybeLazy { + /// Create a [`MaybeLazy`] from an borrowed `T`. + #[inline] + pub const fn borrowed(a: &'static T) -> Self { + MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Borrowed(a)) } + } + + /// Create a [`MaybeLazy`] from an borrowed `T`. + #[inline] + pub const fn owned(a: T::Owned) -> Self { + MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Owned(a)) } + } + + /// Create a [`MaybeLazy`] from a function-able `F`. + #[inline] + pub const fn lazied(f: F) -> Self { + MaybeLazy { inner: MaybeLazyInner::Lazy(LazyLock::new(f)) } + } +} + +impl MaybeLazy { + /// Create a [`MaybeLazy`] from a function pointer. + #[inline] + pub const fn lazy(a: fn() -> T::Owned) -> Self { + Self::lazied(a) + } +} + +impl, F: FnOnce() -> T::Owned> Clone + for MaybeLazy +{ + #[inline] + fn clone(&self) -> Self { + MaybeLazy { + inner: MaybeLazyInner::Cow(match &self.inner { + MaybeLazyInner::Lazy(f) => Cow::Owned((*f).to_owned()), + MaybeLazyInner::Cow(c) => c.clone(), + }), + } + } +} + +impl, F: FnOnce() -> T::Owned> Default + for MaybeLazy +{ + #[inline] + fn default() -> MaybeLazy { + MaybeLazy::owned(T::Owned::default()) + } +} + +// `Debug`, `Display` and other traits below are implemented in terms of this `Deref` +impl>, F: FnOnce() -> T::Owned> Deref + for MaybeLazy +{ + type Target = T; + + #[inline] + fn deref(&self) -> &T { + match &self.inner { + MaybeLazyInner::Lazy(f) => (&**f).borrow(), + MaybeLazyInner::Cow(c) => &*c, + } + } +} + +impl + Debug, F: FnOnce() -> T::Owned> Debug + for MaybeLazy +{ + #[inline] + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Debug::fmt(&**self, fmt) + } +} + +impl + Display, F: FnOnce() -> T::Owned> Display + for MaybeLazy +{ + #[inline] + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Display::fmt(&**self, fmt) + } +} + +impl T::Owned> AsRef for MaybeLazy { + #[inline] + fn as_ref(&self) -> &T { + &**self + } +} + +impl< + T1: ?Sized + PartialEq + ToOwned, + T2: ?Sized + ToOwned, + F1: FnOnce() -> T1::Owned, + F2: FnOnce() -> T2::Owned, +> PartialEq> for MaybeLazy +{ + #[inline] + fn eq(&self, other: &MaybeLazy) -> bool { + PartialEq::eq(&**self, &**other) + } +} + +impl String> PartialEq<&str> for MaybeLazy { + #[inline] + fn eq(&self, other: &&str) -> bool { + &**self == *other + } +} + +impl String> From<&'static str> for MaybeLazy { + #[inline] + fn from(s: &'static str) -> MaybeLazy { + MaybeLazy::borrowed(s) + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 42860b1059ed7..df16162492acc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -39,6 +39,7 @@ use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors use crate::json::{Json, ToJson}; use crate::spec::abi::Abi; use crate::spec::crt_objects::CrtObjects; +use crate::spec::maybe_lazy::MaybeLazy; use rustc_fs_util::try_canonicalize; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -55,6 +56,7 @@ use tracing::debug; pub mod abi; pub mod crt_objects; +pub mod maybe_lazy; mod base; pub use base::apple::deployment_target as current_apple_deployment_target; From 5a71834f993bb6a87e29fd71a7ca4c7fa67a9db1 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 23 Jun 2024 13:45:21 +0200 Subject: [PATCH 2/2] Move CRT Objects fields to `MaybeLazy` --- compiler/rustc_target/src/spec/crt_objects.rs | 60 ++++++++++++------- compiler/rustc_target/src/spec/mod.rs | 12 ++-- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs index 53f710b8f9e14..c542c690e8f72 100644 --- a/compiler/rustc_target/src/spec/crt_objects.rs +++ b/compiler/rustc_target/src/spec/crt_objects.rs @@ -40,28 +40,42 @@ //! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710) //! when linking in self-contained mode. -use crate::spec::LinkOutputKind; +use crate::spec::{LinkOutputKind, MaybeLazy}; use std::borrow::Cow; use std::collections::BTreeMap; +type LazyCrtObjectsArgs = &'static [(LinkOutputKind, &'static [&'static str])]; +pub struct LazyCrtObjectsState(LazyCrtObjectsArgs); + +impl FnOnce<()> for LazyCrtObjectsState { + type Output = CrtObjects; + extern "rust-call" fn call_once(self, _args: ()) -> Self::Output { + self.0.iter().map(|(z, k)| (*z, k.iter().map(|b| (*b).into()).collect())).collect() + } +} + pub type CrtObjects = BTreeMap>>; +pub type LazyCrtObjects = MaybeLazy; -pub(super) fn new(obj_table: &[(LinkOutputKind, &[&'static str])]) -> CrtObjects { - obj_table.iter().map(|(z, k)| (*z, k.iter().map(|b| (*b).into()).collect())).collect() +#[inline] +pub(super) fn new(obj_table: LazyCrtObjectsArgs) -> LazyCrtObjects { + MaybeLazy::lazied(LazyCrtObjectsState(obj_table)) } -pub(super) fn all(obj: &'static str) -> CrtObjects { - new(&[ - (LinkOutputKind::DynamicNoPicExe, &[obj]), - (LinkOutputKind::DynamicPicExe, &[obj]), - (LinkOutputKind::StaticNoPicExe, &[obj]), - (LinkOutputKind::StaticPicExe, &[obj]), - (LinkOutputKind::DynamicDylib, &[obj]), - (LinkOutputKind::StaticDylib, &[obj]), - ]) +macro_rules! all { + ($obj: literal) => { + new(&[ + (LinkOutputKind::DynamicNoPicExe, &[$obj]), + (LinkOutputKind::DynamicPicExe, &[$obj]), + (LinkOutputKind::StaticNoPicExe, &[$obj]), + (LinkOutputKind::StaticPicExe, &[$obj]), + (LinkOutputKind::DynamicDylib, &[$obj]), + (LinkOutputKind::StaticDylib, &[$obj]), + ]) + }; } -pub(super) fn pre_musl_self_contained() -> CrtObjects { +pub(super) fn pre_musl_self_contained() -> LazyCrtObjects { new(&[ (LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o", "crtbegin.o"]), (LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o", "crtbeginS.o"]), @@ -72,7 +86,7 @@ pub(super) fn pre_musl_self_contained() -> CrtObjects { ]) } -pub(super) fn post_musl_self_contained() -> CrtObjects { +pub(super) fn post_musl_self_contained() -> LazyCrtObjects { new(&[ (LinkOutputKind::DynamicNoPicExe, &["crtend.o", "crtn.o"]), (LinkOutputKind::DynamicPicExe, &["crtendS.o", "crtn.o"]), @@ -83,7 +97,7 @@ pub(super) fn post_musl_self_contained() -> CrtObjects { ]) } -pub(super) fn pre_mingw_self_contained() -> CrtObjects { +pub(super) fn pre_mingw_self_contained() -> LazyCrtObjects { new(&[ (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]), (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]), @@ -94,19 +108,19 @@ pub(super) fn pre_mingw_self_contained() -> CrtObjects { ]) } -pub(super) fn post_mingw_self_contained() -> CrtObjects { - all("rsend.o") +pub(super) fn post_mingw_self_contained() -> LazyCrtObjects { + all!("rsend.o") } -pub(super) fn pre_mingw() -> CrtObjects { - all("rsbegin.o") +pub(super) fn pre_mingw() -> LazyCrtObjects { + all!("rsbegin.o") } -pub(super) fn post_mingw() -> CrtObjects { - all("rsend.o") +pub(super) fn post_mingw() -> LazyCrtObjects { + all!("rsend.o") } -pub(super) fn pre_wasi_self_contained() -> CrtObjects { +pub(super) fn pre_wasi_self_contained() -> LazyCrtObjects { // Use crt1-command.o instead of crt1.o to enable support for new-style // commands. See https://reviews.llvm.org/D81689 for more info. new(&[ @@ -118,6 +132,6 @@ pub(super) fn pre_wasi_self_contained() -> CrtObjects { ]) } -pub(super) fn post_wasi_self_contained() -> CrtObjects { +pub(super) fn post_wasi_self_contained() -> LazyCrtObjects { new(&[]) } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index df16162492acc..9821d8e52e49c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -38,7 +38,7 @@ use crate::abi::call::Conv; use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors}; use crate::json::{Json, ToJson}; use crate::spec::abi::Abi; -use crate::spec::crt_objects::CrtObjects; +use crate::spec::crt_objects::{CrtObjects, LazyCrtObjects}; use crate::spec::maybe_lazy::MaybeLazy; use rustc_fs_util::try_canonicalize; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; @@ -2016,11 +2016,11 @@ pub struct TargetOptions { linker_is_gnu_json: bool, /// Objects to link before and after all other object code. - pub pre_link_objects: CrtObjects, - pub post_link_objects: CrtObjects, + pub pre_link_objects: LazyCrtObjects, + pub post_link_objects: LazyCrtObjects, /// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled. - pub pre_link_objects_self_contained: CrtObjects, - pub post_link_objects_self_contained: CrtObjects, + pub pre_link_objects_self_contained: LazyCrtObjects, + pub post_link_objects_self_contained: LazyCrtObjects, /// Behavior for the self-contained linking mode: inferred for some targets, or explicitly /// enabled (in bulk, or with individual components). pub link_self_contained: LinkSelfContainedDefault, @@ -3097,7 +3097,7 @@ impl Target { args.insert(kind, v); } - base.$key_name = args; + base.$key_name = MaybeLazy::owned(args); } } ); ($key_name:ident = $json_name:expr, link_args) => ( {