Skip to content

Commit 661a5ad

Browse files
committed
Auto merge of #26173 - pnkfelix:fsk-trans-nzmove-take3, r=nikomatsakis
Add dropflag hints (stack-local booleans) for unfragmented paths in trans. Part of #5016. Added code to maintain these hints at runtime, and to conditionalize drop-filling and calls to destructors. In this early stage of my incremental implementation strategy, we are using hints, so we are always free to leave out a flag for a path -- then we just pass `None` as the dropflag hint in the corresponding schedule cleanup call. But, once a path has a hint, we must at least maintain it: i.e. if the hint exists, we must ensure it is never set to "moved" if the data in question might actually have been initialized. It remains sound to conservatively set the hint to "initialized" as long as the true drop-flag embedded in the value itself is up-to-date. I hope the commit series has been broken up to be readable; most of the commits in the series should build (though I did not always check this). ---- Oh, I think this technically qualifies as a: [breaking-change] because it removes drop-filling in some cases where one could previously observe it. That should only affect `unsafe` code; no safe code should be able to inspect whether the drop-fill was present or not. For an example of code that needed to change to account for this, see commit a81c24ae0216ab47df59acd724f8a33124fb6d97 (a unit test of the `move_val_init` intrinsic). I have not encountered actual code that needed to be updated to account for the change, since this should only be skipping the drop-filling on *moved* values, not on dropped one, and so even types that use `unsafe_no_drop_flag` should be unchanged by this particular PR. (Their time will come later.)
2 parents ec49d01 + b4dd765 commit 661a5ad

File tree

19 files changed

+832
-164
lines changed

19 files changed

+832
-164
lines changed

src/librustc/middle/ty.rs

+39
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,44 @@ pub struct ctxt<'tcx> {
957957
/// Maps a cast expression to its kind. This is keyed on the
958958
/// *from* expression of the cast, not the cast itself.
959959
pub cast_kinds: RefCell<NodeMap<cast::CastKind>>,
960+
961+
/// Maps Fn items to a collection of fragment infos.
962+
///
963+
/// The main goal is to identify data (each of which may be moved
964+
/// or assigned) whose subparts are not moved nor assigned
965+
/// (i.e. their state is *unfragmented*) and corresponding ast
966+
/// nodes where the path to that data is moved or assigned.
967+
///
968+
/// In the long term, unfragmented values will have their
969+
/// destructor entirely driven by a single stack-local drop-flag,
970+
/// and their parents, the collections of the unfragmented values
971+
/// (or more simply, "fragmented values"), are mapped to the
972+
/// corresponding collections of stack-local drop-flags.
973+
///
974+
/// (However, in the short term that is not the case; e.g. some
975+
/// unfragmented paths still need to be zeroed, namely when they
976+
/// reference parent data from an outer scope that was not
977+
/// entirely moved, and therefore that needs to be zeroed so that
978+
/// we do not get double-drop when we hit the end of the parent
979+
/// scope.)
980+
///
981+
/// Also: currently the table solely holds keys for node-ids of
982+
/// unfragmented values (see `FragmentInfo` enum definition), but
983+
/// longer-term we will need to also store mappings from
984+
/// fragmented data to the set of unfragmented pieces that
985+
/// constitute it.
986+
pub fragment_infos: RefCell<DefIdMap<Vec<FragmentInfo>>>,
987+
}
988+
989+
/// Describes the fragment-state associated with a NodeId.
990+
///
991+
/// Currently only unfragmented paths have entries in the table,
992+
/// but longer-term this enum is expected to expand to also
993+
/// include data for fragmented paths.
994+
#[derive(Copy, Clone, Debug)]
995+
pub enum FragmentInfo {
996+
Moved { var: NodeId, move_expr: NodeId },
997+
Assigned { var: NodeId, assign_expr: NodeId, assignee_id: NodeId },
960998
}
961999

9621000
impl<'tcx> ctxt<'tcx> {
@@ -3498,6 +3536,7 @@ impl<'tcx> ctxt<'tcx> {
34983536
const_qualif_map: RefCell::new(NodeMap()),
34993537
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
35003538
cast_kinds: RefCell::new(NodeMap()),
3539+
fragment_infos: RefCell::new(DefIdMap()),
35013540
}, f)
35023541
}
35033542

src/librustc/session/config.rs

+2
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
594594
"Force drop flag checks on or off"),
595595
trace_macros: bool = (false, parse_bool,
596596
"For every macro invocation, print its name and arguments"),
597+
disable_nonzeroing_move_hints: bool = (false, parse_bool,
598+
"Force nonzeroing move optimization off"),
597599
}
598600

599601
pub fn default_lib_output() -> CrateType {

src/librustc/session/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ impl Session {
272272
pub fn print_enum_sizes(&self) -> bool {
273273
self.opts.debugging_opts.print_enum_sizes
274274
}
275+
pub fn nonzeroing_move_hints(&self) -> bool {
276+
!self.opts.debugging_opts.disable_nonzeroing_move_hints
277+
}
275278
pub fn sysroot<'a>(&'a self) -> &'a Path {
276279
match self.opts.maybe_sysroot {
277280
Some (ref sysroot) => sysroot,

src/librustc_borrowck/borrowck/check_loans.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc<LoanPath<'tcx>>) -> Rc<LoanPath<'
8686
struct CheckLoanCtxt<'a, 'tcx: 'a> {
8787
bccx: &'a BorrowckCtxt<'a, 'tcx>,
8888
dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
89-
move_data: move_data::FlowedMoveData<'a, 'tcx>,
89+
move_data: &'a move_data::FlowedMoveData<'a, 'tcx>,
9090
all_loans: &'a [Loan<'tcx>],
9191
param_env: &'a ty::ParameterEnvironment<'a, 'tcx>,
9292
}
@@ -191,7 +191,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
191191

192192
pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
193193
dfcx_loans: &LoanDataFlow<'b, 'tcx>,
194-
move_data: move_data::FlowedMoveData<'c, 'tcx>,
194+
move_data: &move_data::FlowedMoveData<'c, 'tcx>,
195195
all_loans: &[Loan<'tcx>],
196196
fn_id: ast::NodeId,
197197
decl: &ast::FnDecl,

src/librustc_borrowck/borrowck/fragments.rs

+87-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use self::Fragment::*;
1616

1717
use borrowck::InteriorKind::{InteriorField, InteriorElement};
18-
use borrowck::LoanPath;
18+
use borrowck::{self, LoanPath};
1919
use borrowck::LoanPathKind::{LpVar, LpUpvar, LpDowncast, LpExtend};
2020
use borrowck::LoanPathElem::{LpDeref, LpInterior};
2121
use borrowck::move_data::InvalidMovePathIndex;
@@ -59,6 +59,84 @@ impl Fragment {
5959
}
6060
}
6161

62+
pub fn build_unfragmented_map(this: &mut borrowck::BorrowckCtxt,
63+
move_data: &MoveData,
64+
id: ast::NodeId) {
65+
let fr = &move_data.fragments.borrow();
66+
67+
// For now, don't care about other kinds of fragments; the precise
68+
// classfication of all paths for non-zeroing *drop* needs them,
69+
// but the loose approximation used by non-zeroing moves does not.
70+
let moved_leaf_paths = fr.moved_leaf_paths();
71+
let assigned_leaf_paths = fr.assigned_leaf_paths();
72+
73+
let mut fragment_infos = Vec::with_capacity(moved_leaf_paths.len());
74+
75+
let find_var_id = |move_path_index: MovePathIndex| -> Option<ast::NodeId> {
76+
let lp = move_data.path_loan_path(move_path_index);
77+
match lp.kind {
78+
LpVar(var_id) => Some(var_id),
79+
LpUpvar(ty::UpvarId { var_id, closure_expr_id }) => {
80+
// The `var_id` is unique *relative to* the current function.
81+
// (Check that we are indeed talking about the same function.)
82+
assert_eq!(id, closure_expr_id);
83+
Some(var_id)
84+
}
85+
LpDowncast(..) | LpExtend(..) => {
86+
// This simple implementation of non-zeroing move does
87+
// not attempt to deal with tracking substructure
88+
// accurately in the general case.
89+
None
90+
}
91+
}
92+
};
93+
94+
let moves = move_data.moves.borrow();
95+
for &move_path_index in moved_leaf_paths {
96+
let var_id = match find_var_id(move_path_index) {
97+
None => continue,
98+
Some(var_id) => var_id,
99+
};
100+
101+
move_data.each_applicable_move(move_path_index, |move_index| {
102+
let info = ty::FragmentInfo::Moved {
103+
var: var_id,
104+
move_expr: moves[move_index.get()].id,
105+
};
106+
debug!("fragment_infos push({:?} \
107+
due to move_path_index: {} move_index: {}",
108+
info, move_path_index.get(), move_index.get());
109+
fragment_infos.push(info);
110+
true
111+
});
112+
}
113+
114+
for &move_path_index in assigned_leaf_paths {
115+
let var_id = match find_var_id(move_path_index) {
116+
None => continue,
117+
Some(var_id) => var_id,
118+
};
119+
120+
let var_assigns = move_data.var_assignments.borrow();
121+
for var_assign in var_assigns.iter()
122+
.filter(|&assign| assign.path == move_path_index)
123+
{
124+
let info = ty::FragmentInfo::Assigned {
125+
var: var_id,
126+
assign_expr: var_assign.id,
127+
assignee_id: var_assign.assignee_id,
128+
};
129+
debug!("fragment_infos push({:?} due to var_assignment", info);
130+
fragment_infos.push(info);
131+
}
132+
}
133+
134+
let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut();
135+
let fn_did = ast::DefId { krate: ast::LOCAL_CRATE, node: id };
136+
let prev = fraginfo_map.insert(fn_did, fragment_infos);
137+
assert!(prev.is_none());
138+
}
139+
62140
pub struct FragmentSets {
63141
/// During move_data construction, `moved_leaf_paths` tracks paths
64142
/// that have been used directly by being moved out of. When
@@ -103,6 +181,14 @@ impl FragmentSets {
103181
}
104182
}
105183

184+
pub fn moved_leaf_paths(&self) -> &[MovePathIndex] {
185+
&self.moved_leaf_paths
186+
}
187+
188+
pub fn assigned_leaf_paths(&self) -> &[MovePathIndex] {
189+
&self.assigned_leaf_paths
190+
}
191+
106192
pub fn add_move(&mut self, path_index: MovePathIndex) {
107193
self.moved_leaf_paths.push(path_index);
108194
}

src/librustc_borrowck/borrowck/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,13 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
166166
this.tcx,
167167
sp,
168168
id);
169+
move_data::fragments::build_unfragmented_map(this,
170+
&flowed_moves.move_data,
171+
id);
169172

170173
check_loans::check_loans(this,
171174
&loan_dfcx,
172-
flowed_moves,
175+
&flowed_moves,
173176
&all_loans[..],
174177
id,
175178
decl,

src/librustc_borrowck/borrowck/move_data.rs

+4
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ pub struct Assignment {
159159

160160
/// span of node where assignment occurs
161161
pub span: Span,
162+
163+
/// id for l-value expression on lhs of assignment
164+
pub assignee_id: ast::NodeId,
162165
}
163166

164167
#[derive(Copy, Clone)]
@@ -412,6 +415,7 @@ impl<'tcx> MoveData<'tcx> {
412415
path: path_index,
413416
id: assign_id,
414417
span: span,
418+
assignee_id: assignee_id,
415419
};
416420

417421
if self.is_var_path(path_index) {

0 commit comments

Comments
 (0)