Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup old trans #38302

Merged
merged 103 commits into from
Dec 21, 2016
Merged
Changes from 1 commit
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
bf7d453
Refactor Block into BlockAndBuilder
Mark-Simulacrum Dec 11, 2016
3f17ab9
Remove unreachable and terminated from Block
Mark-Simulacrum Dec 11, 2016
59ef51c
Replace build.rs with calling functions on builder directly
Mark-Simulacrum Dec 11, 2016
e77d928
Add notes regarding malloc_raw_dyn being unwind incompatible
Mark-Simulacrum Dec 11, 2016
ad0a901
Remove *_builder
Mark-Simulacrum Dec 11, 2016
fec59c5
Replace lpad().and_then(..) with None
Mark-Simulacrum Dec 11, 2016
3dbd141
Remove unused map_block
Mark-Simulacrum Dec 12, 2016
8f3d824
Remove common::Block.
Mark-Simulacrum Dec 12, 2016
86b2bdb
Rename LandingPad to Funclet
Mark-Simulacrum Dec 12, 2016
ed989d3
Simple cleanups/inlines in cleanup
Mark-Simulacrum Dec 12, 2016
5a36f88
Remove debug_loc from CleanupScope and privatize various helpers
Mark-Simulacrum Dec 12, 2016
ec518a0
Remove EarlyExitLabel, it only has one variant and is as such useless
Mark-Simulacrum Dec 12, 2016
2842912
Remove DropValue.is_immediate
Mark-Simulacrum Dec 12, 2016
48715a1
Reformatting
Mark-Simulacrum Dec 12, 2016
da971b7
Pull out get_or_create landing pad to avoid issues with dynamic borro…
Mark-Simulacrum Dec 12, 2016
85ef02d
Only one DropValue per CleanupScope
Mark-Simulacrum Dec 13, 2016
6412f31
Propagate CleanupScope::needs_invoke being always true
Mark-Simulacrum Dec 13, 2016
91707dc
Merge need_invoke and needs_invoke
Mark-Simulacrum Dec 13, 2016
51dfba1
Refactor Vec<CleanupScope> into Option<CleanupScope>.
Mark-Simulacrum Dec 13, 2016
28d00e7
Remove cleanup scope from FunctionContext
Mark-Simulacrum Dec 14, 2016
cd57bbe
Refactor get_landing_pad to take a CleanupScope
Mark-Simulacrum Dec 14, 2016
3265afa
Inline and simplify Callee::call duplicates.
Mark-Simulacrum Dec 14, 2016
6441c97
Remove push_ctxt
Mark-Simulacrum Dec 15, 2016
6710af3
Slightly simplify tvec::slice_for_each
Mark-Simulacrum Dec 15, 2016
3169169
Deduplicate store_operand_direct and store_operand
Mark-Simulacrum Dec 15, 2016
c7f8b0c
Eagerly evaluate landing pads for cleanup scopes
Mark-Simulacrum Dec 15, 2016
b10d89a
Move around code in cleanup for a more logical ordering, and fix comm…
Mark-Simulacrum Dec 15, 2016
14ae76d
Unbox FunctionDebugContextData.
Mark-Simulacrum Dec 15, 2016
dda6c8c
Inline base::malloc_raw_dyn.
Mark-Simulacrum Dec 16, 2016
5bdcc22
Remove FIXME
Mark-Simulacrum Dec 16, 2016
da23332
Remove remaining traces of block_arena
Mark-Simulacrum Dec 16, 2016
e0ccc81
Remove needless allows
Mark-Simulacrum Dec 16, 2016
28f511c
Remove global Builder
Mark-Simulacrum Dec 16, 2016
bc0b172
Remove BlockAndBuilder.funclet
Mark-Simulacrum Dec 16, 2016
be981dc
Start FunctionContext privatization and reduction
Mark-Simulacrum Dec 16, 2016
8201645
Remove DebugLoc.
Mark-Simulacrum Dec 16, 2016
5262113
Remove fcx.span
Mark-Simulacrum Dec 16, 2016
bf8614b
Rename Builder::alloca to dynamic_alloca
Mark-Simulacrum Dec 16, 2016
cbbdb73
Remove FunctionContext::cleanup, replacing it with a Drop impl.
Mark-Simulacrum Dec 16, 2016
c4f6173
Replace init with get_entry_block.
Mark-Simulacrum Dec 16, 2016
8ed1120
Minor cleanup to context
Mark-Simulacrum Dec 16, 2016
755850f
Merge OwnedBuilder and Builder
Mark-Simulacrum Dec 17, 2016
85ab080
Remove global builder
Mark-Simulacrum Dec 17, 2016
05d107d
Inline validate_substs
Mark-Simulacrum Dec 17, 2016
65f0400
Remove FunctionContext.landingpad_alloca.
Mark-Simulacrum Dec 17, 2016
9c38a54
Inline FunctionContext.mir
Mark-Simulacrum Dec 17, 2016
cc1e210
Inline trans_exchange_free
Mark-Simulacrum Dec 17, 2016
449c6d8
Simplify basic_block.rs
Mark-Simulacrum Dec 17, 2016
88b2024
Cleanup instruction counting
Mark-Simulacrum Dec 17, 2016
21bd747
Remove unused functions in abi
Mark-Simulacrum Dec 17, 2016
9a19853
Remove unused imports
Mark-Simulacrum Dec 17, 2016
937001a
Refactor Callee::call to take bcx by-reference.
Mark-Simulacrum Dec 17, 2016
1804131
Remove Ref::clone for MirContext mir
Mark-Simulacrum Dec 17, 2016
f051c60
Reduce extensions to FunctionContext in cleanup.
Mark-Simulacrum Dec 17, 2016
c693bcc
Inline memfill and merge with memset_intrinsic.
Mark-Simulacrum Dec 17, 2016
611e90b
Simplify intrinsic match statement
Mark-Simulacrum Dec 17, 2016
99816a6
Further simplify intrinsic matching
Mark-Simulacrum Dec 18, 2016
b48e74b
Rename 'blk and 'bcx to 'a
Mark-Simulacrum Dec 18, 2016
515d14f
Inline/Replace finish with build_return_block
Mark-Simulacrum Dec 18, 2016
97a2096
Inline and cleanup build_return_block
Mark-Simulacrum Dec 18, 2016
1173db0
Inline last remaining use of Callee::call and delete unused code
Mark-Simulacrum Dec 18, 2016
a802b9f
Inline get_funclet
Mark-Simulacrum Dec 18, 2016
fc8c280
Remove lifetime parameter
Mark-Simulacrum Dec 18, 2016
2b9a0ef
Move debug_context to MirContext from FunctionContext
Mark-Simulacrum Dec 18, 2016
a42a342
Move param_env onto SharedCrateContext, and move functions which need…
Mark-Simulacrum Dec 18, 2016
e10695f
Move param_substs onto MirContext
Mark-Simulacrum Dec 18, 2016
0a71b38
Remove llretslotptr from FunctionContext
Mark-Simulacrum Dec 18, 2016
4c7041e
Don't special case abort/unreachable intrinsics
Mark-Simulacrum Dec 18, 2016
2bda3b7
Inline and simplify init_cpad
Mark-Simulacrum Dec 19, 2016
63a0d85
Make add_incoming_to_phi call slightly less confusing.
Mark-Simulacrum Dec 19, 2016
f9f1406
Rebase fixes
Mark-Simulacrum Dec 19, 2016
6e3d8cd
Fix and cleanup callee shims
Mark-Simulacrum Dec 19, 2016
dd1890f
Remove unreachable call to unreachable
Mark-Simulacrum Dec 19, 2016
7f5dffb
Make debuginfo take debug_context instead of MirContext
Mark-Simulacrum Dec 19, 2016
a445199
Remove public ccx function on MirContext
Mark-Simulacrum Dec 19, 2016
0256f60
Move debug info check into create_function_debug_context
Mark-Simulacrum Dec 19, 2016
5301d38
Remove unused bcx from LocalAnalyzer.
Mark-Simulacrum Dec 19, 2016
7f87163
Simplify funclets creation.
Mark-Simulacrum Dec 19, 2016
5ef85dd
Change param_env to empty_param_env
Mark-Simulacrum Dec 19, 2016
22bf541
Clean up uses of set_personality_fn.
Mark-Simulacrum Dec 19, 2016
f11721a
Add helper function to set debug locations
Mark-Simulacrum Dec 19, 2016
f103ea4
Remove unecessary logic.
Mark-Simulacrum Dec 19, 2016
88202c5
Replace bcx.ccx() with bcx.ccx
Mark-Simulacrum Dec 19, 2016
15c9e5e
Mutate llargs instead of reconstructing it.
Mark-Simulacrum Dec 20, 2016
6fac0a1
Change *.fcx.ccx to *.ccx
Mark-Simulacrum Dec 20, 2016
d55e739
Do not use BAB after calling unreachable.
Mark-Simulacrum Dec 20, 2016
6f368e6
Use fn_ty directly
Mark-Simulacrum Dec 20, 2016
0d5a8ad
Move get_landing_pad onto DropVal.
Mark-Simulacrum Dec 20, 2016
6a1ec55
Remove needless check
Mark-Simulacrum Dec 20, 2016
b9f1064
Inline make_drop_glue
Mark-Simulacrum Dec 20, 2016
98a13ff
Remove outdated comment
Mark-Simulacrum Dec 20, 2016
295ea0d
Reduce coerce_unsized_into to one call
Mark-Simulacrum Dec 20, 2016
15b9b27
slice_for_each gives a reference already
Mark-Simulacrum Dec 20, 2016
bd009dc
Remove fn_ty from FunctionContext
Mark-Simulacrum Dec 20, 2016
3198797
Remove outdated comment
Mark-Simulacrum Dec 20, 2016
57914f6
Move eh_personality() onto CrateContext
Mark-Simulacrum Dec 20, 2016
07cf2a9
Simplify callee by removing is_indirect branch.
Mark-Simulacrum Dec 20, 2016
654131c
Add unreachable() after calls to eh_unwind_resume.
Mark-Simulacrum Dec 20, 2016
a811f60
Simplify get_landing_pad by inlining UnwindKind.
Mark-Simulacrum Dec 20, 2016
a9b5c63
Move eh_unwind_resume into CrateContext
Mark-Simulacrum Dec 20, 2016
c1bc5e5
Improve cache quality for eh_personality.
Mark-Simulacrum Dec 20, 2016
079abd0
Reuse cleanup pad declared at start of block.
Mark-Simulacrum Dec 20, 2016
0013d4c
Fix rebase errors.
Mark-Simulacrum Dec 21, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 60 additions & 184 deletions src/librustc_trans/cleanup.rs
Original file line number Diff line number Diff line change
@@ -11,108 +11,12 @@
//! ## The Cleanup module
//!
//! The cleanup module tracks what values need to be cleaned up as scopes
//! are exited, either via panic or just normal control flow. The basic
//! idea is that the function context maintains a stack of cleanup scopes
//! that are pushed/popped as we traverse the AST tree. There is typically
//! at least one cleanup scope per AST node; some AST nodes may introduce
//! additional temporary scopes.
//! are exited, either via panic or just normal control flow.
//!
//! Cleanup items can be scheduled into any of the scopes on the stack.
//! Typically, when a scope is popped, we will also generate the code for
//! each of its cleanups at that time. This corresponds to a normal exit
//! from a block (for example, an expression completing evaluation
//! successfully without panic). However, it is also possible to pop a
//! block *without* executing its cleanups; this is typically used to
//! guard intermediate values that must be cleaned up on panic, but not
//! if everything goes right. See the section on custom scopes below for
//! more details.
//!
//! Cleanup scopes come in three kinds:
//!
//! - **AST scopes:** each AST node in a function body has a corresponding
//! AST scope. We push the AST scope when we start generate code for an AST
//! node and pop it once the AST node has been fully generated.
//! - **Loop scopes:** loops have an additional cleanup scope. Cleanups are
//! never scheduled into loop scopes; instead, they are used to record the
//! basic blocks that we should branch to when a `continue` or `break` statement
//! is encountered.
//! - **Custom scopes:** custom scopes are typically used to ensure cleanup
//! of intermediate values.
//!
//! ### When to schedule cleanup
//!
//! Although the cleanup system is intended to *feel* fairly declarative,
//! it's still important to time calls to `schedule_clean()` correctly.
//! Basically, you should not schedule cleanup for memory until it has
//! been initialized, because if an unwind should occur before the memory
//! is fully initialized, then the cleanup will run and try to free or
//! drop uninitialized memory. If the initialization itself produces
//! byproducts that need to be freed, then you should use temporary custom
//! scopes to ensure that those byproducts will get freed on unwind. For
//! example, an expression like `box foo()` will first allocate a box in the
//! heap and then call `foo()` -- if `foo()` should panic, this box needs
//! to be *shallowly* freed.
//!
//! ### Long-distance jumps
//!
//! In addition to popping a scope, which corresponds to normal control
//! flow exiting the scope, we may also *jump out* of a scope into some
//! earlier scope on the stack. This can occur in response to a `return`,
//! `break`, or `continue` statement, but also in response to panic. In
//! any of these cases, we will generate a series of cleanup blocks for
//! each of the scopes that is exited. So, if the stack contains scopes A
//! ... Z, and we break out of a loop whose corresponding cleanup scope is
//! X, we would generate cleanup blocks for the cleanups in X, Y, and Z.
//! After cleanup is done we would branch to the exit point for scope X.
//! But if panic should occur, we would generate cleanups for all the
//! scopes from A to Z and then resume the unwind process afterwards.
//!
//! To avoid generating tons of code, we cache the cleanup blocks that we
//! create for breaks, returns, unwinds, and other jumps. Whenever a new
//! cleanup is scheduled, though, we must clear these cached blocks. A
//! possible improvement would be to keep the cached blocks but simply
//! generate a new block which performs the additional cleanup and then
//! branches to the existing cached blocks.
//!
//! ### AST and loop cleanup scopes
//!
//! AST cleanup scopes are pushed when we begin and end processing an AST
//! node. They are used to house cleanups related to rvalue temporary that
//! get referenced (e.g., due to an expression like `&Foo()`). Whenever an
//! AST scope is popped, we always trans all the cleanups, adding the cleanup
//! code after the postdominator of the AST node.
//!
//! AST nodes that represent breakable loops also push a loop scope; the
//! loop scope never has any actual cleanups, it's just used to point to
//! the basic blocks where control should flow after a "continue" or
//! "break" statement. Popping a loop scope never generates code.
//!
//! ### Custom cleanup scopes
//!
//! Custom cleanup scopes are used for a variety of purposes. The most
//! common though is to handle temporary byproducts, where cleanup only
//! needs to occur on panic. The general strategy is to push a custom
//! cleanup scope, schedule *shallow* cleanups into the custom scope, and
//! then pop the custom scope (without transing the cleanups) when
//! execution succeeds normally. This way the cleanups are only trans'd on
//! unwind, and only up until the point where execution succeeded, at
//! which time the complete value should be stored in an lvalue or some
//! other place where normal cleanup applies.
//!
//! To spell it out, here is an example. Imagine an expression `box expr`.
//! We would basically:
//!
//! 1. Push a custom cleanup scope C.
//! 2. Allocate the box.
//! 3. Schedule a shallow free in the scope C.
//! 4. Trans `expr` into the box.
//! 5. Pop the scope C.
//! 6. Return the box as an rvalue.
//!
//! This way, if a panic occurs while transing `expr`, the custom
//! cleanup scope C is pushed and hence the box will be freed. The trans
//! code for `expr` itself is responsible for freeing any other byproducts
//! that may be in play.
//! Typically, when a scope is finished, we generate the cleanup code. This
//! corresponds to a normal exit from a block (for example, an expression
//! completing evaluation successfully without panic).
use llvm::{BasicBlockRef, ValueRef};
use base::{self, Lifetime};
@@ -131,9 +35,17 @@ pub struct CleanupScope<'tcx> {
pub landing_pad: Option<BasicBlockRef>,
}

#[derive(Copy, Clone, Debug)]
pub struct CustomScopeIndex {
index: usize
#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
val: ValueRef,
ty: Ty<'tcx>,
skip_dtor: bool,
}

impl<'tcx> DropValue<'tcx> {
fn trans<'blk>(&self, funclet: Option<&'blk Funclet>, bcx: &BlockAndBuilder<'blk, 'tcx>) {
glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
}
}

#[derive(Copy, Clone, Debug)]
@@ -142,6 +54,44 @@ enum UnwindKind {
CleanupPad(ValueRef),
}

impl UnwindKind {
/// Generates a branch going from `bcx` to `to_llbb` where `self` is
/// the exit label attached to the start of `bcx`.
///
/// Transitions from an exit label to other exit labels depend on the type
/// of label. For example with MSVC exceptions unwind exit labels will use
/// the `cleanupret` instruction instead of the `br` instruction.
fn branch(&self, bcx: &BlockAndBuilder, to_llbb: BasicBlockRef) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be inlined?

match *self {
UnwindKind::CleanupPad(pad) => {
bcx.cleanup_ret(pad, Some(to_llbb));
}
UnwindKind::LandingPad => {
bcx.br(to_llbb);
}
}
}

fn get_funclet(&self, bcx: &BlockAndBuilder) -> Option<Funclet> {
match *self {
UnwindKind::CleanupPad(_) => {
let pad = bcx.cleanup_pad(None, &[]);
Funclet::msvc(pad)
},
UnwindKind::LandingPad => Funclet::gnu(),
}
}
}

impl PartialEq for UnwindKind {
fn eq(&self, label: &UnwindKind) -> bool {
match (*self, *label) {
(UnwindKind::LandingPad, UnwindKind::LandingPad) |
(UnwindKind::CleanupPad(..), UnwindKind::CleanupPad(..)) => true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a weird implementation, is it ever used?

_ => false,
}
}
}
impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
pub fn trans_scope(
&self,
@@ -186,9 +136,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
};

debug!("schedule_drop_adt_contents(val={:?}, ty={:?}) skip_dtor={}",
Value(val),
ty,
drop.skip_dtor);
Value(val), ty, drop.skip_dtor);

Some(CleanupScope::new(self, drop))
}
@@ -259,27 +207,9 @@ impl<'tcx> CleanupScope<'tcx> {
UnwindKind::LandingPad
};

// Generate the cleanup block and branch to it.
let cleanup_llbb = CleanupScope::trans_cleanups_to_exit_scope(fcx, val, drop_val);
val.branch(&mut pad_bcx, cleanup_llbb);

return pad_bcx.llbb();
}

/// Used when the caller wishes to jump to an early exit, such as a return,
/// break, continue, or unwind. This function will generate all cleanups
/// between the top of the stack and the exit `label` and return a basic
/// block that the caller can branch to.
fn trans_cleanups_to_exit_scope<'a>(
fcx: &FunctionContext<'a, 'tcx>,
label: UnwindKind,
drop_val: &DropValue<'tcx>
) -> BasicBlockRef {
debug!("trans_cleanups_to_exit_scope label={:?}`", label);

// Generate a block that will resume unwinding to the calling function
let bcx = fcx.build_new_block("resume");
match label {
match val {
UnwindKind::LandingPad => {
let addr = fcx.landingpad_alloca.get().unwrap();
let lp = bcx.load(addr);
@@ -299,68 +229,14 @@ impl<'tcx> CleanupScope<'tcx> {
let mut cleanup = fcx.build_new_block("clean_custom_");

// Insert cleanup instructions into the cleanup block
drop_val.trans(label.get_funclet(&cleanup).as_ref(), &cleanup);
drop_val.trans(val.get_funclet(&cleanup).as_ref(), &cleanup);

// Insert instruction into cleanup block to branch to the exit
label.branch(&mut cleanup, bcx.llbb());

debug!("trans_cleanups_to_exit_scope: llbb={:?}", cleanup.llbb());

cleanup.llbb()
}
}

impl UnwindKind {
/// Generates a branch going from `bcx` to `to_llbb` where `self` is
/// the exit label attached to the start of `bcx`.
///
/// Transitions from an exit label to other exit labels depend on the type
/// of label. For example with MSVC exceptions unwind exit labels will use
/// the `cleanupret` instruction instead of the `br` instruction.
fn branch(&self, bcx: &BlockAndBuilder, to_llbb: BasicBlockRef) {
match *self {
UnwindKind::CleanupPad(pad) => {
bcx.cleanup_ret(pad, Some(to_llbb));
}
UnwindKind::LandingPad => {
bcx.br(to_llbb);
}
}
}

fn get_funclet(&self, bcx: &BlockAndBuilder) -> Option<Funclet> {
match *self {
UnwindKind::CleanupPad(_) => {
let pad = bcx.cleanup_pad(None, &[]);
Funclet::msvc(pad)
},
UnwindKind::LandingPad => Funclet::gnu(),
}
}
}
val.branch(&mut cleanup, bcx.llbb());

impl PartialEq for UnwindKind {
fn eq(&self, label: &UnwindKind) -> bool {
match (*self, *label) {
(UnwindKind::LandingPad, UnwindKind::LandingPad) |
(UnwindKind::CleanupPad(..), UnwindKind::CleanupPad(..)) => true,
_ => false,
}
}
}

///////////////////////////////////////////////////////////////////////////
// Cleanup types
// Branch into the cleanup block
val.branch(&mut pad_bcx, cleanup.llbb());

#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
val: ValueRef,
ty: Ty<'tcx>,
skip_dtor: bool,
}

impl<'tcx> DropValue<'tcx> {
fn trans<'blk>(&self, funclet: Option<&'blk Funclet>, bcx: &BlockAndBuilder<'blk, 'tcx>) {
glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
return pad_bcx.llbb();
}
}