From 9ddcc594113d9d8a3b9181c4436b767251b876c5 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 17 Mar 2024 17:42:37 -0400 Subject: [PATCH] Omit non-needs_drop drop_in_place in vtables This replaces the drop_in_place reference with null in vtables. On librustc_driver.so, this drops about ~17k dynamic relocations from the output, since many vtables can now be placed in read-only memory, rather than having a relocated pointer included. This makes a tradeoff by adding a null check at vtable call sites. That's hard to avoid without changing the vtable format (e.g., to use a pc-relative relocation instead of an absolute address, and avoid the dynamic relocation that way). But it seems likely that the check is cheap at runtime. --- src/abi/mod.rs | 16 ++++++++++++++++ src/base.rs | 5 +---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 4bcef15ad0475..bd5a88769059f 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -593,6 +593,7 @@ pub(crate) fn codegen_drop<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, source_info: mir::SourceInfo, drop_place: CPlace<'tcx>, + target: BasicBlock, ) { let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); @@ -620,6 +621,12 @@ pub(crate) fn codegen_drop<'tcx>( let ptr = ptr.get_addr(fx); let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable); + let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0); + let target_block = fx.get_block(target); + let continued = fx.bcx.create_block(); + fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]); + fx.bcx.switch_to_block(continued); + // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? let virtual_drop = Instance { @@ -659,6 +666,12 @@ pub(crate) fn codegen_drop<'tcx>( let (data, vtable) = drop_place.to_cvalue(fx).dyn_star_force_data_on_stack(fx); let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable); + let is_null = fx.bcx.ins().icmp_imm(IntCC::Equal, drop_fn, 0); + let target_block = fx.get_block(target); + let continued = fx.bcx.create_block(); + fx.bcx.ins().brif(is_null, target_block, &[], continued, &[]); + fx.bcx.switch_to_block(continued); + let virtual_drop = Instance { def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, @@ -697,4 +710,7 @@ pub(crate) fn codegen_drop<'tcx>( } } } + + let target_block = fx.get_block(target); + fx.bcx.ins().jump(target_block, &[]); } diff --git a/src/base.rs b/src/base.rs index 8d778f736d671..c394844e62593 100644 --- a/src/base.rs +++ b/src/base.rs @@ -548,10 +548,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { } TerminatorKind::Drop { place, target, unwind: _, replace: _ } => { let drop_place = codegen_place(fx, *place); - crate::abi::codegen_drop(fx, source_info, drop_place); - - let target_block = fx.get_block(*target); - fx.bcx.ins().jump(target_block, &[]); + crate::abi::codegen_drop(fx, source_info, drop_place, *target); } }; }