Skip to content

Commit a2a7683

Browse files
committed
Auto merge of rust-lang#90845 - JakobDegen:adt-drop-perf, r=Mark-Simulacrum
Address performance regression introduced by rust-lang#90218 As part of the changes in rust-lang#90218 , the `adt_drop_tys` and friends code stopped recursing through the query system, meaning that intermediate computations did not get cached. This change adds the recursions back in without re-introducing any of the old issues. On local benchmarks this fixes the 5% regressions in rust-lang#90504 ; the wg-grammar regressions didn't seem to move too much. I may take some time later to look into those. Not sure who to request for review here, so will leave it up to whoever gets it.
2 parents 0206312 + 746091c commit a2a7683

File tree

1 file changed

+61
-23
lines changed

1 file changed

+61
-23
lines changed

compiler/rustc_ty_utils/src/needs_drop.rs

+61-23
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
1717
// needs drop.
1818
let adt_has_dtor =
1919
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
20-
let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some();
20+
let res =
21+
drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some();
2122

2223
debug!("needs_drop_raw({:?}) = {:?}", query, res);
2324
res
@@ -27,10 +28,15 @@ fn has_significant_drop_raw<'tcx>(
2728
tcx: TyCtxt<'tcx>,
2829
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
2930
) -> bool {
30-
let res =
31-
drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx))
32-
.next()
33-
.is_some();
31+
let res = drop_tys_helper(
32+
tcx,
33+
query.value,
34+
query.param_env,
35+
adt_consider_insignificant_dtor(tcx),
36+
true,
37+
)
38+
.next()
39+
.is_some();
3440
debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
3541
res
3642
}
@@ -141,9 +147,9 @@ where
141147
Ok(tys) => tys,
142148
};
143149
for required_ty in tys {
144-
let subst_ty =
150+
let required =
145151
tcx.normalize_erasing_regions(self.param_env, required_ty);
146-
queue_type(self, subst_ty);
152+
queue_type(self, required);
147153
}
148154
}
149155
ty::Array(..) | ty::Opaque(..) | ty::Projection(..) | ty::Param(_) => {
@@ -186,39 +192,67 @@ fn drop_tys_helper<'tcx>(
186192
ty: Ty<'tcx>,
187193
param_env: rustc_middle::ty::ParamEnv<'tcx>,
188194
adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
195+
only_significant: bool,
189196
) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
197+
fn with_query_cache<'tcx>(
198+
tcx: TyCtxt<'tcx>,
199+
iter: impl IntoIterator<Item = Ty<'tcx>>,
200+
only_significant: bool,
201+
) -> NeedsDropResult<Vec<Ty<'tcx>>> {
202+
iter.into_iter().try_fold(Vec::new(), |mut vec, subty| {
203+
match subty.kind() {
204+
ty::Adt(adt_id, subst) => {
205+
for subty in if only_significant {
206+
tcx.adt_significant_drop_tys(adt_id.did)?
207+
} else {
208+
tcx.adt_drop_tys(adt_id.did)?
209+
} {
210+
vec.push(subty.subst(tcx, subst));
211+
}
212+
}
213+
_ => vec.push(subty),
214+
};
215+
Ok(vec)
216+
})
217+
}
218+
190219
let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
191220
if adt_def.is_manually_drop() {
192221
debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
193-
return Ok(Vec::new().into_iter());
222+
Ok(Vec::new())
194223
} else if let Some(dtor_info) = adt_has_dtor(adt_def) {
195224
match dtor_info {
196225
DtorType::Significant => {
197226
debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
198-
return Err(AlwaysRequiresDrop);
227+
Err(AlwaysRequiresDrop)
199228
}
200229
DtorType::Insignificant => {
201230
debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);
202231

203232
// Since the destructor is insignificant, we just want to make sure all of
204233
// the passed in type parameters are also insignificant.
205234
// Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
206-
return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
235+
with_query_cache(tcx, substs.types(), only_significant)
207236
}
208237
}
209238
} else if adt_def.is_union() {
210239
debug!("drop_tys_helper: `{:?}` is a union", adt_def);
211-
return Ok(Vec::new().into_iter());
240+
Ok(Vec::new())
241+
} else {
242+
with_query_cache(
243+
tcx,
244+
adt_def.all_fields().map(|field| {
245+
let r = tcx.type_of(field.did).subst(tcx, substs);
246+
debug!(
247+
"drop_tys_helper: Subst into {:?} with {:?} gettng {:?}",
248+
field, substs, r
249+
);
250+
r
251+
}),
252+
only_significant,
253+
)
212254
}
213-
Ok(adt_def
214-
.all_fields()
215-
.map(|field| {
216-
let r = tcx.type_of(field.did).subst(tcx, substs);
217-
debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
218-
r
219-
})
220-
.collect::<Vec<_>>()
221-
.into_iter())
255+
.map(|v| v.into_iter())
222256
};
223257

224258
NeedsDropTypes::new(tcx, param_env, ty, adt_components)
@@ -252,20 +286,24 @@ fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, Alw
252286
// significant.
253287
let adt_has_dtor =
254288
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
255-
drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor)
289+
// `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_substs)`
290+
drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor, false)
256291
.collect::<Result<Vec<_>, _>>()
257292
.map(|components| tcx.intern_type_list(&components))
258293
}
259-
294+
// If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed
295+
// a `tcx.make_ty(def, identity_substs)` and as such it is legal to substitue the generic parameters
296+
// of the ADT into the outputted `ty`s.
260297
fn adt_significant_drop_tys(
261298
tcx: TyCtxt<'_>,
262299
def_id: DefId,
263300
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
264301
drop_tys_helper(
265302
tcx,
266-
tcx.type_of(def_id),
303+
tcx.type_of(def_id), // identical to `tcx.make_adt(def, identity_substs)`
267304
tcx.param_env(def_id),
268305
adt_consider_insignificant_dtor(tcx),
306+
true,
269307
)
270308
.collect::<Result<Vec<_>, _>>()
271309
.map(|components| tcx.intern_type_list(&components))

0 commit comments

Comments
 (0)