Skip to content

Commit cb04e49

Browse files
committed
rewrite drop code
This was triggered by me wanting to address a use of DUMMY_SP, but actually I'm not sure what would be a better span -- I guess the span for the function as a whole.
1 parent f976e22 commit cb04e49

File tree

3 files changed

+85
-83
lines changed

3 files changed

+85
-83
lines changed

src/librustc_mir/build/expr/into.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
256256
block = match value {
257257
Some(value) => unpack!(this.into(&Lvalue::ReturnPointer, block, value)),
258258
None => {
259-
this.cfg.push_assign_unit(block, scope_id, expr_span, &Lvalue::ReturnPointer);
259+
this.cfg.push_assign_unit(block, scope_id,
260+
expr_span, &Lvalue::ReturnPointer);
260261
block
261262
}
262263
};

src/librustc_mir/build/matches/test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
272272
let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
273273

274274
// actual = len(lvalue)
275-
self.cfg.push_assign(block, scope_id, test.span, &actual, Rvalue::Len(lvalue.clone()));
275+
self.cfg.push_assign(block, scope_id, test.span,
276+
&actual, Rvalue::Len(lvalue.clone()));
276277

277278
// expected = <N>
278279
let expected = self.push_usize(block, scope_id, test.span, len);

src/librustc_mir/build/scope.rs

Lines changed: 81 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,20 @@ pub struct Scope<'tcx> {
113113
// This is expected to go away once `box EXPR` becomes a sugar for placement protocol and gets
114114
// desugared in some earlier stage.
115115
free: Option<FreeData<'tcx>>,
116+
117+
/// The cached block for the cleanups-on-diverge path. This block
118+
/// contains a block that will just do a RESUME to an appropriate
119+
/// place. This block does not execute any of the drops or free:
120+
/// each of those has their own cached-blocks, which will branch
121+
/// to this point.
122+
cached_block: Option<BasicBlock>
116123
}
117124

118125
struct DropData<'tcx> {
119126
span: Span,
120127
value: Lvalue<'tcx>,
121128
// NB: per-drop “cache” is necessary for the build_scope_drops function below.
129+
122130
/// The cached block for the cleanups-on-diverge path. This block contains code to run the
123131
/// current drop and all the preceding drops (i.e. those having lower index in Drop’s
124132
/// Scope drop array)
@@ -127,10 +135,13 @@ struct DropData<'tcx> {
127135

128136
struct FreeData<'tcx> {
129137
span: Span,
138+
130139
/// Lvalue containing the allocated box.
131140
value: Lvalue<'tcx>,
141+
132142
/// type of item for which the box was allocated for (i.e. the T in Box<T>).
133143
item_ty: Ty<'tcx>,
144+
134145
/// The cached block containing code to run the free. The block will also execute all the drops
135146
/// in the scope.
136147
cached_block: Option<BasicBlock>
@@ -155,6 +166,7 @@ impl<'tcx> Scope<'tcx> {
155166
/// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
156167
/// larger extent of code.
157168
fn invalidate_cache(&mut self) {
169+
self.cached_block = None;
158170
for dropdata in &mut self.drops {
159171
dropdata.cached_block = None;
160172
}
@@ -234,7 +246,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
234246
id: id,
235247
extent: extent,
236248
drops: vec![],
237-
free: None
249+
free: None,
250+
cached_block: None,
238251
});
239252
self.scope_auxiliary.push(ScopeAuxiliary {
240253
extent: extent,
@@ -288,7 +301,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
288301
block));
289302
if let Some(ref free_data) = scope.free {
290303
let next = self.cfg.start_new_block();
291-
let free = build_free(self.hir.tcx(), tmp.clone(), free_data, next);
304+
let free = build_free(self.hir.tcx(), &tmp, free_data, next);
292305
self.cfg.terminate(block, scope.id, span, free);
293306
block = next;
294307
}
@@ -419,20 +432,16 @@ impl<'a,'tcx> Builder<'a,'tcx> {
419432
}
420433
let unit_temp = self.get_unit_temp();
421434
let Builder { ref mut hir, ref mut cfg, ref mut scopes, .. } = *self;
422-
let mut next_block = None;
423435

424436
// Given an array of scopes, we generate these from the outermost scope to the innermost
425437
// one. Thus for array [S0, S1, S2] with corresponding cleanup blocks [B0, B1, B2], we will
426438
// generate B0 <- B1 <- B2 in left-to-right order. Control flow of the generated blocks
427439
// always ends up at a block with the Resume terminator.
428-
for scope in scopes.iter_mut().filter(|s| !s.drops.is_empty() || s.free.is_some()) {
429-
next_block = Some(build_diverge_scope(hir.tcx(),
430-
cfg,
431-
unit_temp.clone(),
432-
scope,
433-
next_block));
440+
if scopes.iter().any(|scope| !scope.drops.is_empty() || scope.free.is_some()) {
441+
Some(build_diverge_scope(hir.tcx(), cfg, &unit_temp, scopes))
442+
} else {
443+
None
434444
}
435-
scopes.iter().rev().flat_map(|x| x.cached_block()).next()
436445
}
437446

438447
/// Utility function for *non*-scope code to build their own drops
@@ -525,8 +534,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
525534
// FIXME: We should have this as a constant, rather than a stack variable (to not pollute
526535
// icache with cold branch code), however to achieve that we either have to rely on rvalue
527536
// promotion or have some way, in MIR, to create constants.
528-
self.cfg.push_assign(block, scope_id, span, &tuple, // tuple = (message_arg, file_arg, line_arg);
537+
self.cfg.push_assign(block, scope_id, span, &tuple, // [1]
529538
Rvalue::Aggregate(AggregateKind::Tuple, elems));
539+
// [1] tuple = (message_arg, file_arg, line_arg);
530540
// FIXME: is this region really correct here?
531541
self.cfg.push_assign(block, scope_id, span, &tuple_ref, // tuple_ref = &tuple;
532542
Rvalue::Ref(region, BorrowKind::Shared, tuple));
@@ -602,58 +612,42 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
602612

603613
fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>,
604614
cfg: &mut CFG<'tcx>,
605-
unit_temp: Lvalue<'tcx>,
606-
scope: &mut Scope<'tcx>,
607-
target: Option<BasicBlock>)
608-
-> BasicBlock {
609-
debug_assert!(!scope.drops.is_empty() || scope.free.is_some());
610-
611-
// First, we build the drops, iterating the drops array in reverse. We do that so that as soon
612-
// as we find a `cached_block`, we know that we’re finished and don’t need to do anything else.
613-
let mut previous = None;
614-
let mut last_drop_block = None;
615-
for drop_data in scope.drops.iter_mut().rev() {
616-
if let Some(cached_block) = drop_data.cached_block {
617-
if let Some((previous_block, previous_span, previous_value)) = previous {
618-
cfg.terminate(previous_block,
619-
scope.id,
620-
previous_span,
621-
TerminatorKind::Drop {
622-
value: previous_value,
623-
target: cached_block,
624-
unwind: None
625-
});
626-
return last_drop_block.unwrap();
627-
} else {
628-
return cached_block;
629-
}
630-
} else {
631-
let block = cfg.start_new_cleanup_block();
632-
drop_data.cached_block = Some(block);
633-
if let Some((previous_block, previous_span, previous_value)) = previous {
634-
cfg.terminate(previous_block,
635-
scope.id,
636-
previous_span,
637-
TerminatorKind::Drop {
638-
value: previous_value,
639-
target: block,
640-
unwind: None
641-
});
642-
} else {
643-
last_drop_block = Some(block);
644-
}
645-
previous = Some((block, drop_data.span, drop_data.value.clone()));
646-
}
647-
}
648-
649-
// Prepare the end target for this chain.
650-
let mut target = target.unwrap_or_else(||{
651-
let b = cfg.start_new_cleanup_block();
652-
cfg.terminate(b, scope.id, DUMMY_SP, TerminatorKind::Resume); // TODO
653-
b
654-
});
615+
unit_temp: &Lvalue<'tcx>,
616+
scopes: &mut [Scope<'tcx>])
617+
-> BasicBlock
618+
{
619+
assert!(scopes.len() >= 1);
620+
621+
// Build up the drops in **reverse** order. The end result will
622+
// look like:
623+
//
624+
// [drops[n]] -...-> [drops[0]] -> [Free] -> [scopes[..n-1]]
625+
// | |
626+
// +------------------------------------+
627+
// code for scopes[n]
628+
//
629+
// The code in this function reads from right to left. At each
630+
// point, we check for cached blocks representing the
631+
// remainder. If everything is cached, we'll just walk right to
632+
// left reading the cached results but never created anything.
633+
634+
// To start, translate scopes[1..].
635+
let (scope, earlier_scopes) = scopes.split_last_mut().unwrap();
636+
let mut target = if let Some(cached_block) = scope.cached_block {
637+
cached_block
638+
} else if earlier_scopes.is_empty() {
639+
// Diverging from the root scope creates a RESUME terminator.
640+
// FIXME what span to use here?
641+
let resumeblk = cfg.start_new_cleanup_block();
642+
cfg.terminate(resumeblk, scope.id, DUMMY_SP, TerminatorKind::Resume);
643+
resumeblk
644+
} else {
645+
// Diverging from any other scope chains up to the previous scope.
646+
build_diverge_scope(tcx, cfg, unit_temp, earlier_scopes)
647+
};
648+
scope.cached_block = Some(target);
655649

656-
// Then, build the free branching into the prepared target.
650+
// Next, build up any free.
657651
if let Some(ref mut free_data) = scope.free {
658652
target = if let Some(cached_block) = free_data.cached_block {
659653
cached_block
@@ -665,29 +659,35 @@ fn build_diverge_scope<'tcx>(tcx: &TyCtxt<'tcx>,
665659
build_free(tcx, unit_temp, free_data, target));
666660
free_data.cached_block = Some(into);
667661
into
668-
}
669-
};
662+
};
663+
}
670664

671-
if let Some((previous_block, previous_span, previous_value)) = previous {
672-
// Finally, branch into that just-built `target` from the `previous_block`.
673-
cfg.terminate(previous_block,
674-
scope.id,
675-
previous_span,
676-
TerminatorKind::Drop {
677-
value: previous_value,
678-
target: target,
679-
unwind: None
680-
});
681-
last_drop_block.unwrap()
682-
} else {
683-
// If `previous.is_none()`, there were no drops in this scope – we return the
684-
// target.
685-
target
665+
// Next, build up the drops. Here we iterate the vector in
666+
// *forward* order, so that we generate drops[0] first (right to
667+
// left in diagram above).
668+
for drop_data in &mut scope.drops {
669+
target = if let Some(cached_block) = drop_data.cached_block {
670+
cached_block
671+
} else {
672+
let block = cfg.start_new_cleanup_block();
673+
cfg.terminate(block,
674+
scope.id,
675+
drop_data.span,
676+
TerminatorKind::Drop {
677+
value: drop_data.value.clone(),
678+
target: target,
679+
unwind: None
680+
});
681+
drop_data.cached_block = Some(block);
682+
block
683+
};
686684
}
685+
686+
target
687687
}
688688

689689
fn build_free<'tcx>(tcx: &TyCtxt<'tcx>,
690-
unit_temp: Lvalue<'tcx>,
690+
unit_temp: &Lvalue<'tcx>,
691691
data: &FreeData<'tcx>,
692692
target: BasicBlock)
693693
-> TerminatorKind<'tcx> {
@@ -707,7 +707,7 @@ fn build_free<'tcx>(tcx: &TyCtxt<'tcx>,
707707
}
708708
}),
709709
args: vec![Operand::Consume(data.value.clone())],
710-
destination: Some((unit_temp, target)),
710+
destination: Some((unit_temp.clone(), target)),
711711
cleanup: None
712712
}
713713
}

0 commit comments

Comments
 (0)