Skip to content

Commit 72d733c

Browse files
committed
Auto merge of rust-lang#126860 - Urgau:lazy-targets-crt-objects, r=<try>
Lazify CRT objects fields initilization This PR lazify the CRT objects by introducing `MaybeLazy`, a 3-way lazy container (borrowed, owned and lazied state). Split from rust-lang#122703 r? `@petrochenkov`
2 parents 05468cf + 5a71834 commit 72d733c

File tree

4 files changed

+191
-29
lines changed

4 files changed

+191
-29
lines changed

compiler/rustc_target/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
1313
#![doc(rust_logo)]
1414
#![feature(assert_matches)]
15+
#![feature(fn_traits)]
1516
#![feature(iter_intersperse)]
1617
#![feature(let_chains)]
1718
#![feature(min_exhaustive_patterns)]
1819
#![feature(rustc_attrs)]
1920
#![feature(rustdoc_internals)]
21+
#![feature(unboxed_closures)]
2022
// tidy-alphabetical-end
2123

2224
use std::path::{Path, PathBuf};

compiler/rustc_target/src/spec/crt_objects.rs

+37-23
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,42 @@
4040
//! but not gcc's. As a result rustc cannot link with C++ static libraries (#36710)
4141
//! when linking in self-contained mode.
4242
43-
use crate::spec::LinkOutputKind;
43+
use crate::spec::{LinkOutputKind, MaybeLazy};
4444
use std::borrow::Cow;
4545
use std::collections::BTreeMap;
4646

47+
type LazyCrtObjectsArgs = &'static [(LinkOutputKind, &'static [&'static str])];
48+
pub struct LazyCrtObjectsState(LazyCrtObjectsArgs);
49+
50+
impl FnOnce<()> for LazyCrtObjectsState {
51+
type Output = CrtObjects;
52+
extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
53+
self.0.iter().map(|(z, k)| (*z, k.iter().map(|b| (*b).into()).collect())).collect()
54+
}
55+
}
56+
4757
pub type CrtObjects = BTreeMap<LinkOutputKind, Vec<Cow<'static, str>>>;
58+
pub type LazyCrtObjects = MaybeLazy<CrtObjects, LazyCrtObjectsState>;
4859

49-
pub(super) fn new(obj_table: &[(LinkOutputKind, &[&'static str])]) -> CrtObjects {
50-
obj_table.iter().map(|(z, k)| (*z, k.iter().map(|b| (*b).into()).collect())).collect()
60+
#[inline]
61+
pub(super) fn new(obj_table: LazyCrtObjectsArgs) -> LazyCrtObjects {
62+
MaybeLazy::lazied(LazyCrtObjectsState(obj_table))
5163
}
5264

53-
pub(super) fn all(obj: &'static str) -> CrtObjects {
54-
new(&[
55-
(LinkOutputKind::DynamicNoPicExe, &[obj]),
56-
(LinkOutputKind::DynamicPicExe, &[obj]),
57-
(LinkOutputKind::StaticNoPicExe, &[obj]),
58-
(LinkOutputKind::StaticPicExe, &[obj]),
59-
(LinkOutputKind::DynamicDylib, &[obj]),
60-
(LinkOutputKind::StaticDylib, &[obj]),
61-
])
65+
macro_rules! all {
66+
($obj: literal) => {
67+
new(&[
68+
(LinkOutputKind::DynamicNoPicExe, &[$obj]),
69+
(LinkOutputKind::DynamicPicExe, &[$obj]),
70+
(LinkOutputKind::StaticNoPicExe, &[$obj]),
71+
(LinkOutputKind::StaticPicExe, &[$obj]),
72+
(LinkOutputKind::DynamicDylib, &[$obj]),
73+
(LinkOutputKind::StaticDylib, &[$obj]),
74+
])
75+
};
6276
}
6377

64-
pub(super) fn pre_musl_self_contained() -> CrtObjects {
78+
pub(super) fn pre_musl_self_contained() -> LazyCrtObjects {
6579
new(&[
6680
(LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o", "crtbegin.o"]),
6781
(LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o", "crtbeginS.o"]),
@@ -72,7 +86,7 @@ pub(super) fn pre_musl_self_contained() -> CrtObjects {
7286
])
7387
}
7488

75-
pub(super) fn post_musl_self_contained() -> CrtObjects {
89+
pub(super) fn post_musl_self_contained() -> LazyCrtObjects {
7690
new(&[
7791
(LinkOutputKind::DynamicNoPicExe, &["crtend.o", "crtn.o"]),
7892
(LinkOutputKind::DynamicPicExe, &["crtendS.o", "crtn.o"]),
@@ -83,7 +97,7 @@ pub(super) fn post_musl_self_contained() -> CrtObjects {
8397
])
8498
}
8599

86-
pub(super) fn pre_mingw_self_contained() -> CrtObjects {
100+
pub(super) fn pre_mingw_self_contained() -> LazyCrtObjects {
87101
new(&[
88102
(LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
89103
(LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
@@ -94,19 +108,19 @@ pub(super) fn pre_mingw_self_contained() -> CrtObjects {
94108
])
95109
}
96110

97-
pub(super) fn post_mingw_self_contained() -> CrtObjects {
98-
all("rsend.o")
111+
pub(super) fn post_mingw_self_contained() -> LazyCrtObjects {
112+
all!("rsend.o")
99113
}
100114

101-
pub(super) fn pre_mingw() -> CrtObjects {
102-
all("rsbegin.o")
115+
pub(super) fn pre_mingw() -> LazyCrtObjects {
116+
all!("rsbegin.o")
103117
}
104118

105-
pub(super) fn post_mingw() -> CrtObjects {
106-
all("rsend.o")
119+
pub(super) fn post_mingw() -> LazyCrtObjects {
120+
all!("rsend.o")
107121
}
108122

109-
pub(super) fn pre_wasi_self_contained() -> CrtObjects {
123+
pub(super) fn pre_wasi_self_contained() -> LazyCrtObjects {
110124
// Use crt1-command.o instead of crt1.o to enable support for new-style
111125
// commands. See https://reviews.llvm.org/D81689 for more info.
112126
new(&[
@@ -118,6 +132,6 @@ pub(super) fn pre_wasi_self_contained() -> CrtObjects {
118132
])
119133
}
120134

121-
pub(super) fn post_wasi_self_contained() -> CrtObjects {
135+
pub(super) fn post_wasi_self_contained() -> LazyCrtObjects {
122136
new(&[])
123137
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//! A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data.
2+
3+
use std::borrow::{Borrow, Cow};
4+
use std::fmt::{Debug, Display};
5+
use std::ops::Deref;
6+
use std::sync::LazyLock;
7+
8+
enum MaybeLazyInner<T: 'static + ToOwned + ?Sized, F> {
9+
Lazy(LazyLock<T::Owned, F>),
10+
Cow(Cow<'static, T>),
11+
}
12+
13+
/// A custom LazyLock+Cow suitable for holding borrowed, owned or lazy data.
14+
///
15+
/// Technically this structure has 3 states: borrowed, owned and lazy
16+
/// They can all be constructed from the [`MaybeLazy::borrowed`], [`MaybeLazy::owned`] and
17+
/// [`MaybeLazy::lazy`] methods.
18+
#[repr(transparent)]
19+
pub struct MaybeLazy<T: 'static + ToOwned + ?Sized, F = fn() -> <T as ToOwned>::Owned> {
20+
// Inner state.
21+
//
22+
// Not to be inlined since we may want in the future to
23+
// make this struct usable to statics and we might need to
24+
// workaround const-eval limitation (particulary around drop).
25+
inner: MaybeLazyInner<T, F>,
26+
}
27+
28+
impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> MaybeLazy<T, F> {
29+
/// Create a [`MaybeLazy`] from an borrowed `T`.
30+
#[inline]
31+
pub const fn borrowed(a: &'static T) -> Self {
32+
MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Borrowed(a)) }
33+
}
34+
35+
/// Create a [`MaybeLazy`] from an borrowed `T`.
36+
#[inline]
37+
pub const fn owned(a: T::Owned) -> Self {
38+
MaybeLazy { inner: MaybeLazyInner::Cow(Cow::Owned(a)) }
39+
}
40+
41+
/// Create a [`MaybeLazy`] from a function-able `F`.
42+
#[inline]
43+
pub const fn lazied(f: F) -> Self {
44+
MaybeLazy { inner: MaybeLazyInner::Lazy(LazyLock::new(f)) }
45+
}
46+
}
47+
48+
impl<T: 'static + ?Sized + ToOwned> MaybeLazy<T> {
49+
/// Create a [`MaybeLazy`] from a function pointer.
50+
#[inline]
51+
pub const fn lazy(a: fn() -> T::Owned) -> Self {
52+
Self::lazied(a)
53+
}
54+
}
55+
56+
impl<T: 'static + ?Sized + ToOwned<Owned: Clone>, F: FnOnce() -> T::Owned> Clone
57+
for MaybeLazy<T, F>
58+
{
59+
#[inline]
60+
fn clone(&self) -> Self {
61+
MaybeLazy {
62+
inner: MaybeLazyInner::Cow(match &self.inner {
63+
MaybeLazyInner::Lazy(f) => Cow::Owned((*f).to_owned()),
64+
MaybeLazyInner::Cow(c) => c.clone(),
65+
}),
66+
}
67+
}
68+
}
69+
70+
impl<T: 'static + ?Sized + ToOwned<Owned: Default>, F: FnOnce() -> T::Owned> Default
71+
for MaybeLazy<T, F>
72+
{
73+
#[inline]
74+
fn default() -> MaybeLazy<T, F> {
75+
MaybeLazy::owned(T::Owned::default())
76+
}
77+
}
78+
79+
// `Debug`, `Display` and other traits below are implemented in terms of this `Deref`
80+
impl<T: 'static + ?Sized + ToOwned<Owned: Borrow<T>>, F: FnOnce() -> T::Owned> Deref
81+
for MaybeLazy<T, F>
82+
{
83+
type Target = T;
84+
85+
#[inline]
86+
fn deref(&self) -> &T {
87+
match &self.inner {
88+
MaybeLazyInner::Lazy(f) => (&**f).borrow(),
89+
MaybeLazyInner::Cow(c) => &*c,
90+
}
91+
}
92+
}
93+
94+
impl<T: 'static + ?Sized + ToOwned<Owned: Debug> + Debug, F: FnOnce() -> T::Owned> Debug
95+
for MaybeLazy<T, F>
96+
{
97+
#[inline]
98+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99+
Debug::fmt(&**self, fmt)
100+
}
101+
}
102+
103+
impl<T: 'static + ?Sized + ToOwned<Owned: Display> + Display, F: FnOnce() -> T::Owned> Display
104+
for MaybeLazy<T, F>
105+
{
106+
#[inline]
107+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108+
Display::fmt(&**self, fmt)
109+
}
110+
}
111+
112+
impl<T: 'static + ?Sized + ToOwned, F: FnOnce() -> T::Owned> AsRef<T> for MaybeLazy<T, F> {
113+
#[inline]
114+
fn as_ref(&self) -> &T {
115+
&**self
116+
}
117+
}
118+
119+
impl<
120+
T1: ?Sized + PartialEq<T2> + ToOwned,
121+
T2: ?Sized + ToOwned,
122+
F1: FnOnce() -> T1::Owned,
123+
F2: FnOnce() -> T2::Owned,
124+
> PartialEq<MaybeLazy<T2, F2>> for MaybeLazy<T1, F1>
125+
{
126+
#[inline]
127+
fn eq(&self, other: &MaybeLazy<T2, F2>) -> bool {
128+
PartialEq::eq(&**self, &**other)
129+
}
130+
}
131+
132+
impl<F: FnOnce() -> String> PartialEq<&str> for MaybeLazy<str, F> {
133+
#[inline]
134+
fn eq(&self, other: &&str) -> bool {
135+
&**self == *other
136+
}
137+
}
138+
139+
impl<F: FnOnce() -> String> From<&'static str> for MaybeLazy<str, F> {
140+
#[inline]
141+
fn from(s: &'static str) -> MaybeLazy<str, F> {
142+
MaybeLazy::borrowed(s)
143+
}
144+
}

compiler/rustc_target/src/spec/mod.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ use crate::abi::call::Conv;
3838
use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
3939
use crate::json::{Json, ToJson};
4040
use crate::spec::abi::Abi;
41-
use crate::spec::crt_objects::CrtObjects;
41+
use crate::spec::crt_objects::{CrtObjects, LazyCrtObjects};
42+
use crate::spec::maybe_lazy::MaybeLazy;
4243
use rustc_fs_util::try_canonicalize;
4344
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
4445
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
@@ -55,6 +56,7 @@ use tracing::debug;
5556

5657
pub mod abi;
5758
pub mod crt_objects;
59+
pub mod maybe_lazy;
5860

5961
mod base;
6062
pub use base::apple::deployment_target as current_apple_deployment_target;
@@ -2017,11 +2019,11 @@ pub struct TargetOptions {
20172019
linker_is_gnu_json: bool,
20182020

20192021
/// Objects to link before and after all other object code.
2020-
pub pre_link_objects: CrtObjects,
2021-
pub post_link_objects: CrtObjects,
2022+
pub pre_link_objects: LazyCrtObjects,
2023+
pub post_link_objects: LazyCrtObjects,
20222024
/// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled.
2023-
pub pre_link_objects_self_contained: CrtObjects,
2024-
pub post_link_objects_self_contained: CrtObjects,
2025+
pub pre_link_objects_self_contained: LazyCrtObjects,
2026+
pub post_link_objects_self_contained: LazyCrtObjects,
20252027
/// Behavior for the self-contained linking mode: inferred for some targets, or explicitly
20262028
/// enabled (in bulk, or with individual components).
20272029
pub link_self_contained: LinkSelfContainedDefault,
@@ -3098,7 +3100,7 @@ impl Target {
30983100

30993101
args.insert(kind, v);
31003102
}
3101-
base.$key_name = args;
3103+
base.$key_name = MaybeLazy::owned(args);
31023104
}
31033105
} );
31043106
($key_name:ident = $json_name:expr, link_args) => ( {

0 commit comments

Comments
 (0)