Skip to content

Commit 46e801f

Browse files
5: Automatically determine when finalizers can be omitted r=ltratt a=jacob-hughes This PR introduces support for optimising away finalizers for Vecs whose element types can be statically determined not to need dropping. This requires the user to specify `Boehm` as the global allocator in their crate, and the -Zgc-destination-propagation flag must be enabled. Right now, this won't work recursively. In other words, if one were to create a value with the following type: Gc<Vec<Vec<usize>> A finalizer would still be registered unnecessarily. This is because the MIR pass which determines which Vecs are allocated directly in GC space currently looks only at the top-level element type inside a Vec. Gc<Vec<Vec<usize>> ^ ^ | | | +---- No Finalizer +----- Finalizer In order for both finalizers to be removed, one must implement `ManageableContents` for `Vec<usize>`. Co-authored-by: Jacob Hughes <jh@jakehughes.uk>
2 parents 304d1bb + 4a3f939 commit 46e801f

File tree

3 files changed

+60
-39
lines changed

3 files changed

+60
-39
lines changed

src/liballoc/gc.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ impl<T> GcBox<T> {
119119

120120
unsafe {
121121
ptr.copy_from_nonoverlapping(&gcbox, 1);
122-
GcBox::register_finalizer(&mut *ptr);
122+
if !Self::is_manageable_contents() && Self::needs_drop() {
123+
GcBox::register_finalizer(&mut *ptr);
124+
}
123125
}
124126

125127
mem::forget(gcbox);
@@ -134,18 +136,8 @@ impl<T> GcBox<T> {
134136
NonNull::new_unchecked((base_ptr.add(1)) as *mut GcBox<MaybeUninit<T>>)
135137
}
136138
}
137-
}
138-
139-
trait GcBoxExt {
140-
fn register_finalizer(&mut self);
141-
}
142139

143-
impl<T: ManageableContents> GcBoxExt for GcBox<Vec<T>> {
144-
fn register_finalizer(&mut self) {}
145-
}
146-
147-
impl<T> GcBoxExt for GcBox<T> {
148-
default fn register_finalizer(&mut self) {
140+
fn register_finalizer(&mut self) {
149141
unsafe extern "C" fn fshim<T>(obj: *mut c_void, _meta: *mut c_void) {
150142
ManuallyDrop::drop(&mut *(obj as *mut ManuallyDrop<T>));
151143
}
@@ -162,6 +154,38 @@ impl<T> GcBoxExt for GcBox<T> {
162154
}
163155
}
164156

157+
trait IsManageableContents {
158+
fn is_manageable_contents() -> bool;
159+
}
160+
161+
impl<T> IsManageableContents for GcBox<T> {
162+
default fn is_manageable_contents() -> bool {
163+
false
164+
}
165+
}
166+
167+
impl<T: ManageableContents> IsManageableContents for GcBox<Vec<T>> {
168+
fn is_manageable_contents() -> bool {
169+
true
170+
}
171+
}
172+
173+
trait NeedsDrop {
174+
fn needs_drop() -> bool;
175+
}
176+
177+
impl<T> NeedsDrop for GcBox<T> {
178+
default fn needs_drop() -> bool {
179+
mem::needs_drop::<T>()
180+
}
181+
}
182+
183+
impl<T> NeedsDrop for GcBox<Vec<T>> {
184+
fn needs_drop() -> bool {
185+
mem::needs_drop::<T>()
186+
}
187+
}
188+
165189
impl<T> GcBox<MaybeUninit<T>> {
166190
unsafe fn assume_init(&mut self) -> NonNull<GcBox<T>> {
167191
// With T now considered initialized, we must make sure that if GcBox<T>

src/librustc_mir/transform/preallocate_gc_contents.rs

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ pub struct GcPreallocator;
1717

1818
impl<'tcx> MirPass<'tcx> for GcPreallocator {
1919
fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
20-
let param_env = tcx.param_env(source.def_id()).with_reveal_all();
20+
if !tcx.sess.opts.debugging_opts.gc_destination_propagation {
21+
return;
22+
}
2123

24+
let param_env = tcx.param_env(source.def_id()).with_reveal_all();
2225
GcPatcher { tcx, source, param_env }.run_pass(body);
2326
}
2427
}
@@ -46,11 +49,7 @@ impl GcPatcher<'tcx> {
4649
let name = self.tcx.def_path_str(callee_def_id);
4750
let new_term = match name.as_str() {
4851
VEC_WITH_CAPACITY => {
49-
if !ty_impls_manageable_contents(
50-
substs.type_at(0),
51-
self.tcx,
52-
self.param_env,
53-
) {
52+
if elem_ty_must_drop(substs.type_at(0), self.tcx, self.param_env) {
5453
continue;
5554
}
5655
let new_callee = self.tcx.lang_items().vec_with_capacity_fn().unwrap();
@@ -65,11 +64,7 @@ impl GcPatcher<'tcx> {
6564
}
6665
}
6766
VEC_PUSH => {
68-
if !ty_impls_manageable_contents(
69-
substs.type_at(0),
70-
self.tcx,
71-
self.param_env,
72-
) {
67+
if elem_ty_must_drop(substs.type_at(0), self.tcx, self.param_env) {
7368
continue;
7469
}
7570
let new_callee = self.tcx.lang_items().vec_push_gc_fn().unwrap();
@@ -93,20 +88,20 @@ impl GcPatcher<'tcx> {
9388
}
9489
}
9590

96-
fn ty_impls_manageable_contents<'tcx>(
97-
ty: Ty<'tcx>,
98-
tcx: TyCtxt<'tcx>,
99-
param_env: ty::ParamEnv<'tcx>,
100-
) -> bool {
101-
let prealloc_trait_id = tcx.lang_items().manageable_contents_trait().unwrap();
102-
let obligation = predicate_for_trait_def(
103-
tcx,
104-
param_env,
105-
traits::ObligationCause::dummy(),
106-
prealloc_trait_id,
107-
0,
108-
ty,
109-
&[],
110-
);
111-
tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
91+
fn elem_ty_must_drop<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
92+
if !ty.needs_drop(tcx, param_env) {
93+
return false;
94+
} else {
95+
let prealloc_trait_id = tcx.lang_items().manageable_contents_trait().unwrap();
96+
let obligation = predicate_for_trait_def(
97+
tcx,
98+
param_env,
99+
traits::ObligationCause::dummy(),
100+
prealloc_trait_id,
101+
0,
102+
ty,
103+
&[],
104+
);
105+
tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
106+
}
112107
}

src/librustc_session/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,4 +973,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
973973
"link native libraries in the linker invocation (default: yes)"),
974974
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
975975
"hash algorithm of source files in debug info (`md5`, or `sha1`)"),
976+
gc_destination_propagation: bool = (false, parse_bool, [TRACKED],
977+
"only enable this if Boehm is the global allocator"),
976978
}

0 commit comments

Comments
 (0)