Skip to content

Lazify CRT objects fields initilization #126860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_target/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
60 changes: 37 additions & 23 deletions compiler/rustc_target/src/spec/crt_objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<LinkOutputKind, Vec<Cow<'static, str>>>;
pub type LazyCrtObjects = MaybeLazy<CrtObjects, LazyCrtObjectsState>;

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"]),
Expand All @@ -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"]),
Expand All @@ -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"]),
Expand All @@ -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(&[
Expand All @@ -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(&[])
}
144 changes: 144 additions & 0 deletions compiler/rustc_target/src/spec/maybe_lazy.rs
Original file line number Diff line number Diff line change
@@ -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<T: 'static + ToOwned + ?Sized, F> {
Lazy(LazyLock<T::Owned, F>),
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<T: 'static + ToOwned + ?Sized, F = fn() -> <T as ToOwned>::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<T, F>,
}

impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> MaybeLazy<T, F> {
/// 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<T: 'static + ?Sized + ToOwned> MaybeLazy<T> {
/// Create a [`MaybeLazy`] from a function pointer.
#[inline]
pub const fn lazy(a: fn() -> T::Owned) -> Self {
Self::lazied(a)
}
}

impl<T: 'static + ?Sized + ToOwned<Owned: Clone>, F: FnOnce() -> T::Owned> Clone
for MaybeLazy<T, F>
{
#[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<T: 'static + ?Sized + ToOwned<Owned: Default>, F: FnOnce() -> T::Owned> Default
for MaybeLazy<T, F>
{
#[inline]
fn default() -> MaybeLazy<T, F> {
MaybeLazy::owned(T::Owned::default())
}
}

// `Debug`, `Display` and other traits below are implemented in terms of this `Deref`
impl<T: 'static + ?Sized + ToOwned<Owned: Borrow<T>>, F: FnOnce() -> T::Owned> Deref
for MaybeLazy<T, F>
{
type Target = T;

#[inline]
fn deref(&self) -> &T {
match &self.inner {
MaybeLazyInner::Lazy(f) => (&**f).borrow(),
MaybeLazyInner::Cow(c) => &*c,
}
}
}

impl<T: 'static + ?Sized + ToOwned<Owned: Debug> + Debug, F: FnOnce() -> T::Owned> Debug
for MaybeLazy<T, F>
{
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&**self, fmt)
}
}

impl<T: 'static + ?Sized + ToOwned<Owned: Display> + Display, F: FnOnce() -> T::Owned> Display
for MaybeLazy<T, F>
{
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&**self, fmt)
}
}

impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> AsRef<T> for MaybeLazy<T, F> {
#[inline]
fn as_ref(&self) -> &T {
&**self
}
}

impl<
T1: ?Sized + PartialEq<T2> + ToOwned,
T2: ?Sized + ToOwned,
F1: FnOnce() -> T1::Owned,
F2: FnOnce() -> T2::Owned,
> PartialEq<MaybeLazy<T2, F2>> for MaybeLazy<T1, F1>
{
#[inline]
fn eq(&self, other: &MaybeLazy<T2, F2>) -> bool {
PartialEq::eq(&**self, &**other)
}
}

impl<F: FnOnce() -> String> PartialEq<&str> for MaybeLazy<str, F> {
#[inline]
fn eq(&self, other: &&str) -> bool {
&**self == *other
}
}

impl<F: FnOnce() -> String> From<&'static str> for MaybeLazy<str, F> {
#[inline]
fn from(s: &'static str) -> MaybeLazy<str, F> {
MaybeLazy::borrowed(s)
}
}
14 changes: 8 additions & 6 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ 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};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
Expand All @@ -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;
Expand Down Expand Up @@ -2014,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,
Expand Down Expand Up @@ -3095,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) => ( {
Expand Down
Loading