Skip to content

Commit 9443527

Browse files
committed
Auto merge of #143290 - azhogin:azhogin/link-pub-async-impls, r=<try>
pub async fn impl is monomorphized when func itself is monomorphized Implentation coroutine (`func::{closure#0}`) is monomorphized, when func itself is monomorphized. Currently, when `pub async fn foo(..)` is exported from lib and used in several dependent crates, only 'header' function is monomorphized in the defining crate. 'header' function, returning coroutine object, is monomorphized, but the coroutine's poll function (which actually implements all the logic for the function) is not. In such situation, `func::{closure#0}` will be monomorphized in every dependency. This PR adds monomorphization for `func::{closure#0}` (coroutine poll function), when func itself is monomorphized. Simple test with one lib async function and ten dependent crates (executable) that use the function, shows 5-7% compilation time improvement (single-threaded).
2 parents f51c987 + d6e2c24 commit 9443527

File tree

11 files changed

+137
-13
lines changed

11 files changed

+137
-13
lines changed

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1510,7 +1510,20 @@ impl<'v> RootCollector<'_, 'v> {
15101510
fn process_nested_body(&mut self, def_id: LocalDefId) {
15111511
match self.tcx.def_kind(def_id) {
15121512
DefKind::Closure => {
1513-
if self.strategy == MonoItemCollectionStrategy::Eager
1513+
// for 'pub async fn foo(..)' also trying to monomorphize foo::{closure}
1514+
let is_pub_fn_coroutine =
1515+
match *self.tcx.type_of(def_id).instantiate_identity().kind() {
1516+
ty::Coroutine(cor_id, _args) => {
1517+
let tcx = self.tcx;
1518+
let parent_id = tcx.parent(cor_id);
1519+
tcx.def_kind(parent_id) == DefKind::Fn
1520+
&& tcx.asyncness(parent_id).is_async()
1521+
&& tcx.visibility(parent_id).is_public()
1522+
}
1523+
ty::Closure(..) | ty::CoroutineClosure(..) => false,
1524+
_ => unreachable!(),
1525+
};
1526+
if (self.strategy == MonoItemCollectionStrategy::Eager || is_pub_fn_coroutine)
15141527
&& !self
15151528
.tcx
15161529
.generics_of(self.tcx.typeck_root_def_id(def_id.to_def_id()))
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ edition: 2024
2+
// When pub async fn is monomorphized, its implementation coroutine is also monomorphized
3+
// (with -Zlink-pub-async-impls)
4+
//@ compile-flags: -Zlink-pub-async-impls --crate-type=lib
5+
6+
//~ MONO_ITEM fn async_fn @@
7+
//~ MONO_ITEM fn async_fn::{closure#0} @@
8+
#[unsafe(no_mangle)]
9+
pub async fn async_fn(x: u64) -> bool {
10+
true
11+
}

tests/codegen/async-fn-debug-awaitee-field.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ pub async fn async_fn_test() {
1818

1919
pub async fn foo() {}
2020

21+
// NONMSVC: [[AWAITEE_TYPE:![0-9]*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]],
22+
// MSVC: [[AWAITEE_TYPE:![0-9]*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>",
23+
// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo",
2124
// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]],
2225
// MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::async_fn_test::async_fn_env$0>",
2326
// NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test",
2427
// CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]],
25-
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]],
26-
// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]],
27-
// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0>",
28-
// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo",
28+
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE]],

tests/coverage/async.cov-map

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,21 @@ Number of file 0 mappings: 3
103103
Highest counter ID seen: (none)
104104

105105
Function name: async::g
106-
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 16]
106+
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 12]
107107
Number of files: 1
108108
- file 0 => $DIR/async.rs
109109
Number of expressions: 0
110110
Number of file 0 mappings: 1
111-
- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 22)
111+
- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 18)
112112
Highest counter ID seen: c0
113113

114114
Function name: async::g::{closure#0} (unused)
115-
Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 17, 00, 18, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
115+
Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 13, 00, 14, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
116116
Number of files: 1
117117
- file 0 => $DIR/async.rs
118118
Number of expressions: 0
119119
Number of file 0 mappings: 12
120-
- Code(Zero) at (prev + 27, 23) to (start + 0, 24)
120+
- Code(Zero) at (prev + 27, 19) to (start + 0, 20)
121121
- Code(Zero) at (prev + 1, 11) to (start + 0, 12)
122122
- Code(Zero) at (prev + 1, 9) to (start + 0, 10)
123123
- Code(Zero) at (prev + 0, 14) to (start + 0, 23)

tests/coverage/async.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ async fn f() -> u8 { 1 }
2424

2525
async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()`
2626

27-
pub async fn g(x: u8) {
27+
async fn g(x: u8) {
2828
match x {
2929
y if e().await == y => (),
3030
y if f().await == y => (),

tests/ui/async-await/future-sizes/async-awaiting-fut.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ compile-flags: -Z print-type-sizes --crate-type lib
1+
//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib
22
//@ edition:2021
33
//@ build-pass
44
//@ ignore-pass

tests/ui/async-await/future-sizes/async-awaiting-fut.stdout

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,36 @@ print-type-size variant `Returned`: 1024 bytes
4848
print-type-size upvar `.arg`: 1024 bytes
4949
print-type-size variant `Panicked`: 1024 bytes
5050
print-type-size upvar `.arg`: 1024 bytes
51+
print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
52+
print-type-size field `.waker`: 8 bytes
53+
print-type-size field `.local_waker`: 8 bytes
54+
print-type-size field `.ext`: 16 bytes
55+
print-type-size field `._marker`: 0 bytes
56+
print-type-size field `._marker2`: 0 bytes
57+
print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
58+
print-type-size field `.file_bytes_with_nul`: 16 bytes
59+
print-type-size field `.line`: 4 bytes
60+
print-type-size field `.col`: 4 bytes
61+
print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
62+
print-type-size variant `Some`: 16 bytes
63+
print-type-size field `.0`: 16 bytes
64+
print-type-size variant `None`: 0 bytes
65+
print-type-size field `.0`: 0 bytes
66+
print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
67+
print-type-size field `.0`: 16 bytes
68+
print-type-size type: `std::pin::Pin<&mut {async fn body of big_fut()}>`: 8 bytes, alignment: 8 bytes
69+
print-type-size field `.pointer`: 8 bytes
70+
print-type-size type: `std::pin::Pin<&mut {async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 8 bytes, alignment: 8 bytes
71+
print-type-size field `.pointer`: 8 bytes
72+
print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes
73+
print-type-size field `.pointer`: 8 bytes
74+
print-type-size type: `std::pin::Pin<&mut {async fn body of wait()}>`: 8 bytes, alignment: 8 bytes
75+
print-type-size field `.pointer`: 8 bytes
76+
print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes
77+
print-type-size field `._vtable_ptr`: 8 bytes
78+
print-type-size field `._phantom`: 0 bytes
79+
print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes
80+
print-type-size field `.pointer`: 8 bytes
5181
print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes
5282
print-type-size field `.value`: 1 bytes
5383
print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes
@@ -70,3 +100,6 @@ print-type-size discriminant: 1 bytes
70100
print-type-size variant `Unresumed`: 0 bytes
71101
print-type-size variant `Returned`: 0 bytes
72102
print-type-size variant `Panicked`: 0 bytes
103+
print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
104+
print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
105+
print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes

tests/ui/async-await/future-sizes/large-arg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ compile-flags: -Z print-type-sizes --crate-type=lib
1+
//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type=lib
22
//@ edition: 2021
33
//@ build-pass
44
//@ ignore-pass

tests/ui/async-await/future-sizes/large-arg.stdout

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,41 @@ print-type-size variant `Returned`: 1024 bytes
5858
print-type-size upvar `.t`: 1024 bytes
5959
print-type-size variant `Panicked`: 1024 bytes
6060
print-type-size upvar `.t`: 1024 bytes
61+
print-type-size type: `std::task::Context<'_>`: 32 bytes, alignment: 8 bytes
62+
print-type-size field `.waker`: 8 bytes
63+
print-type-size field `.local_waker`: 8 bytes
64+
print-type-size field `.ext`: 16 bytes
65+
print-type-size field `._marker`: 0 bytes
66+
print-type-size field `._marker2`: 0 bytes
67+
print-type-size type: `std::panic::Location<'_>`: 24 bytes, alignment: 8 bytes
68+
print-type-size field `.file_bytes_with_nul`: 16 bytes
69+
print-type-size field `.line`: 4 bytes
70+
print-type-size field `.col`: 4 bytes
71+
print-type-size type: `core::task::wake::ExtData<'_>`: 16 bytes, alignment: 8 bytes
72+
print-type-size variant `Some`: 16 bytes
73+
print-type-size field `.0`: 16 bytes
74+
print-type-size variant `None`: 0 bytes
75+
print-type-size field `.0`: 0 bytes
76+
print-type-size type: `std::panic::AssertUnwindSafe<core::task::wake::ExtData<'_>>`: 16 bytes, alignment: 8 bytes
77+
print-type-size field `.0`: 16 bytes
78+
print-type-size type: `std::pin::Pin<&mut {async fn body of a<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes
79+
print-type-size field `.pointer`: 8 bytes
80+
print-type-size type: `std::pin::Pin<&mut {async fn body of b<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes
81+
print-type-size field `.pointer`: 8 bytes
82+
print-type-size type: `std::pin::Pin<&mut {async fn body of c<[u8; 1024]>()}>`: 8 bytes, alignment: 8 bytes
83+
print-type-size field `.pointer`: 8 bytes
84+
print-type-size type: `std::pin::Pin<&mut {async fn body of test()}>`: 8 bytes, alignment: 8 bytes
85+
print-type-size field `.pointer`: 8 bytes
86+
print-type-size type: `std::ptr::DynMetadata<dyn std::any::Any>`: 8 bytes, alignment: 8 bytes
87+
print-type-size field `._vtable_ptr`: 8 bytes
88+
print-type-size field `._phantom`: 0 bytes
89+
print-type-size type: `std::ptr::NonNull<std::ptr::metadata::VTable>`: 8 bytes, alignment: 8 bytes
90+
print-type-size field `.pointer`: 8 bytes
91+
print-type-size type: `std::task::Poll<()>`: 1 bytes, alignment: 1 bytes
92+
print-type-size discriminant: 1 bytes
93+
print-type-size variant `Ready`: 0 bytes
94+
print-type-size field `.0`: 0 bytes
95+
print-type-size variant `Pending`: 0 bytes
96+
print-type-size type: `std::marker::PhantomData<*mut ()>`: 0 bytes, alignment: 1 bytes
97+
print-type-size type: `std::marker::PhantomData<dyn std::any::Any>`: 0 bytes, alignment: 1 bytes
98+
print-type-size type: `std::marker::PhantomData<fn(&()) -> &()>`: 0 bytes, alignment: 1 bytes

tests/ui/print_type_sizes/async.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ compile-flags: -Z print-type-sizes --crate-type lib
1+
//@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib
22
//@ edition:2021
33
//@ build-pass
44
//@ ignore-pass

0 commit comments

Comments
 (0)