diff options
| -rw-r--r-- | src/librustc_trans/trans/_match.rs | 72 | ||||
| -rw-r--r-- | src/librustc_trans/trans/adt.rs | 14 | ||||
| -rw-r--r-- | src/librustc_trans/trans/base.rs | 53 | ||||
| -rw-r--r-- | src/librustc_trans/trans/cleanup.rs | 48 | ||||
| -rw-r--r-- | src/librustc_trans/trans/closure.rs | 4 | ||||
| -rw-r--r-- | src/librustc_trans/trans/common.rs | 6 | ||||
| -rw-r--r-- | src/librustc_trans/trans/datum.rs | 70 | ||||
| -rw-r--r-- | src/librustc_trans/trans/expr.rs | 29 | ||||
| -rw-r--r-- | src/librustc_trans/trans/glue.rs | 29 | ||||
| -rw-r--r-- | src/librustc_trans/trans/tvec.rs | 4 |
10 files changed, 259 insertions, 70 deletions
diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 08be1fd2e4c..7a491a628e5 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -205,7 +205,7 @@ use trans::build::{AddCase, And, Br, CondBr, GEPi, InBoundsGEP, Load, PointerCas use trans::build::{Not, Store, Sub, add_comment}; use trans::build; use trans::callee; -use trans::cleanup::{self, CleanupMethods}; +use trans::cleanup::{self, CleanupMethods, DropHintMethods}; use trans::common::*; use trans::consts; use trans::datum::*; @@ -947,14 +947,14 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, TrByCopy(llbinding) | TrByMoveIntoCopy(llbinding) => { let llval = Load(bcx, binding_info.llmatch); - let lval = match binding_info.trmode { + let lvalue = match binding_info.trmode { TrByCopy(..) => Lvalue::new("_match::insert_lllocals"), TrByMoveIntoCopy(..) => Lvalue::match_input("_match::insert_lllocals", bcx, binding_info.id), _ => unreachable!(), }; - let datum = Datum::new(llval, binding_info.ty, lval); + let datum = Datum::new(llval, binding_info.ty, lvalue); call_lifetime_start(bcx, llbinding); bcx = datum.store_to(bcx, llbinding); if let Some(cs) = cs { @@ -971,14 +971,15 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, TrByRef => (binding_info.llmatch, true), }; - let lval = Lvalue::local("_match::insert_lllocals", - bcx, - binding_info.id, - aliases_other_state); - let datum = Datum::new(llval, binding_info.ty, lval); + let lvalue = Lvalue::local("_match::insert_lllocals", + bcx, + binding_info.id, + aliases_other_state); + let datum = Datum::new(llval, binding_info.ty, lvalue); if let Some(cs) = cs { + let opt_datum = lvalue.dropflag_hint(bcx); bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch); - bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty); + bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty, opt_datum); } debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval)); @@ -1505,13 +1506,13 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, // but during matching we need to store a *T as explained // above llmatch = alloca_no_lifetime(bcx, - llvariable_ty.ptr_to(), - &bcx.name(name)); + llvariable_ty.ptr_to(), + &bcx.name(name)); trmode = TrByMoveRef; } ast::BindByRef(_) => { llmatch = alloca_no_lifetime(bcx, - llvariable_ty, + llvariable_ty, &bcx.name(name)); trmode = TrByRef; } @@ -1631,7 +1632,25 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = mk_binding_alloca( bcx, p_id, path1.node.name, scope, (), "_match::store_local::create_dummy_locals", - |(), bcx, llval, ty| { drop_done_fill_mem(bcx, llval, ty); bcx }); + |(), bcx, Datum { val: llval, ty, kind }| { + // Dummy-locals start out uninitialized, so set their + // drop-flag hints (if any) to "moved." + if let Some(hint) = kind.dropflag_hint(bcx) { + let moved_hint = adt::DTOR_MOVED_HINT as usize; + debug!("store moved_hint={} for hint={:?}, uninitialized dummy", + moved_hint, hint); + Store(bcx, C_u8(bcx.fcx.ccx, moved_hint), hint.to_value().value()); + } + + if kind.drop_flag_info.must_zero() { + // if no drop-flag hint, or the hint requires + // we maintain the embedded drop-flag, then + // mark embedded drop-flag(s) as moved + // (i.e. "already dropped"). + drop_done_fill_mem(bcx, llval, ty); + } + bcx + }); }); bcx } @@ -1654,8 +1673,8 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return mk_binding_alloca( bcx, pat.id, ident.name, var_scope, (), "_match::store_local", - |(), bcx, v, _| expr::trans_into(bcx, &**init_expr, - expr::SaveIn(v))); + |(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &**init_expr, + expr::SaveIn(v))); } None => {} @@ -1684,23 +1703,23 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, caller_name: &'static str, populate: F) -> Block<'blk, 'tcx> where - F: FnOnce(A, Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>, + F: FnOnce(A, Block<'blk, 'tcx>, Datum<'tcx, Lvalue>) -> Block<'blk, 'tcx>, { let var_ty = node_id_type(bcx, p_id); // Allocate memory on stack for the binding. let llval = alloc_ty(bcx, var_ty, &bcx.name(name)); + let lvalue = Lvalue::binding(caller_name, bcx, p_id, name); + let datum = Datum::new(llval, var_ty, lvalue); // Subtle: be sure that we *populate* the memory *before* // we schedule the cleanup. - let bcx = populate(arg, bcx, llval, var_ty); + let bcx = populate(arg, bcx, datum); bcx.fcx.schedule_lifetime_end(cleanup_scope, llval); - bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty); + bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty, lvalue.dropflag_hint(bcx)); // Now that memory is initialized and has cleanup scheduled, - // create the datum and insert into the local variable map. - let lval = Lvalue::binding(caller_name, bcx, p_id, name); - let datum = Datum::new(llval, var_ty, lval); + // insert datum into the local variable map. bcx.fcx.lllocals.borrow_mut().insert(p_id, datum); bcx } @@ -1746,7 +1765,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = mk_binding_alloca( bcx, pat.id, path1.node.name, cleanup_scope, (), "_match::bind_irrefutable_pat", - |(), bcx, llval, ty| { + |(), bcx, Datum { val: llval, ty, kind: _ }| { match pat_binding_mode { ast::BindByValue(_) => { // By value binding: move the value that `val` @@ -1854,10 +1873,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::PatBox(ref inner) => { let llbox = Load(bcx, val.val); bcx = bind_irrefutable_pat( - bcx, - &**inner, - MatchInput::from_val(llbox), - cleanup_scope); + bcx, &**inner, MatchInput::from_val(llbox), cleanup_scope); } ast::PatRegion(ref inner, _) => { let loaded_val = Load(bcx, val.val); @@ -1884,13 +1900,13 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, .chain(slice.iter()) .chain(after.iter()) .zip(extracted.vals) - .fold(bcx, |bcx, (inner, elem)| + .fold(bcx, |bcx, (inner, elem)| { bind_irrefutable_pat( bcx, &**inner, MatchInput::from_val(elem), cleanup_scope) - ); + }); } ast::PatMac(..) => { bcx.sess().span_bug(pat.span, "unexpanded macro"); diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index d2753f5b78f..b47d2dd4112 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -163,6 +163,20 @@ macro_rules! repeat_u8_as_u64 { (repeat_u8_as_u32!($name) as u64)) } } +/// `DTOR_NEEDED_HINT` is a stack-local hint that just means +/// "we do not know whether the destructor has run or not; check the +/// drop-flag embedded in the value itself." +pub const DTOR_NEEDED_HINT: u8 = 0x3d; + +/// `DTOR_MOVED_HINT` is a stack-local hint that means "this value has +/// definitely been moved; you do not need to run its destructor." +/// +/// (However, for now, such values may still end up being explicitly +/// zeroed by the generated code; this is the distinction between +/// `datum::DropFlagInfo::ZeroAndMaintain` versus +/// `datum::DropFlagInfo::DontZeroJustUse`.) +pub const DTOR_MOVED_HINT: u8 = 0x2d; + pub const DTOR_NEEDED: u8 = 0xd4; pub const DTOR_NEEDED_U32: u32 = repeat_u8_as_u32!(DTOR_NEEDED); pub const DTOR_NEEDED_U64: u64 = repeat_u8_as_u64!(DTOR_NEEDED); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index ec7ff4fa748..61e81d75607 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -51,8 +51,7 @@ use trans::attributes; use trans::build::*; use trans::builder::{Builder, noname}; use trans::callee; -use trans::cleanup::CleanupMethods; -use trans::cleanup; +use trans::cleanup::{self, CleanupMethods, DropHint}; use trans::closure; use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral}; use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; @@ -88,7 +87,7 @@ use arena::TypedArena; use libc::c_uint; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::mem; use std::str; use std::{i8, i16, i32, i64}; @@ -1284,6 +1283,54 @@ pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, } } + // Create the drop-flag hints for every unfragmented path in the function. + let tcx = fcx.ccx.tcx(); + let fn_did = ast::DefId { krate: ast::LOCAL_CRATE, node: fcx.id }; + let mut hints = fcx.lldropflag_hints.borrow_mut(); + let fragment_infos = tcx.fragment_infos.borrow(); + + // Intern table for drop-flag hint datums. + let mut seen = HashMap::new(); + + if let Some(fragment_infos) = fragment_infos.get(&fn_did) { + for &info in fragment_infos { + + let make_datum = |id| { + let init_val = C_u8(fcx.ccx, adt::DTOR_NEEDED_HINT as usize); + let llname = &format!("dropflag_hint_{}", id); + debug!("adding hint {}", llname); + let ptr = alloc_ty(entry_bcx, tcx.types.u8, llname); + Store(entry_bcx, init_val, ptr); + let ty = tcx.mk_ptr(ty::TypeAndMut { ty: tcx.types.u8, mutbl: ast::MutMutable }); + let flag = datum::Lvalue::new_dropflag_hint("base::init_function"); + let datum = datum::Datum::new(ptr, ty, flag); + datum + }; + + let (var, datum) = match info { + ty::FragmentInfo::Moved { var, .. } | + ty::FragmentInfo::Assigned { var, .. } => { + let datum = seen.get(&var).cloned().unwrap_or_else(|| { + let datum = make_datum(var); + seen.insert(var, datum.clone()); + datum + }); + (var, datum) + } + }; + match info { + ty::FragmentInfo::Moved { move_expr: expr_id, .. } => { + debug!("FragmentInfo::Moved insert drop hint for {}", expr_id); + hints.insert(expr_id, DropHint::new(var, datum)); + } + ty::FragmentInfo::Assigned { assignee_id: expr_id, .. } => { + debug!("FragmentInfo::Assigned insert drop hint for {}", expr_id); + hints.insert(expr_id, DropHint::new(var, datum)); + } + } + } + } + entry_bcx } diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index fe996020267..b4b0472512e 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -219,6 +219,23 @@ pub struct DropHint<K>(pub ast::NodeId, pub K); pub type DropHintDatum<'tcx> = DropHint<Datum<'tcx, Lvalue>>; pub type DropHintValue = DropHint<ValueRef>; +impl<K> DropHint<K> { + pub fn new(id: ast::NodeId, k: K) -> DropHint<K> { DropHint(id, k) } +} + +impl DropHint<ValueRef> { + pub fn value(&self) -> ValueRef { self.1 } +} + +pub trait DropHintMethods { + type ValueKind; + fn to_value(&self) -> Self::ValueKind; +} +impl<'tcx> DropHintMethods for DropHintDatum<'tcx> { + type ValueKind = DropHintValue; + fn to_value(&self) -> DropHintValue { DropHint(self.0, self.1.val) } +} + impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { /// Invoked when we start to trans the code contained within a new cleanup scope. fn push_ast_cleanup_scope(&self, debug_loc: NodeIdAndSpan) { @@ -389,14 +406,17 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { fn schedule_drop_mem(&self, cleanup_scope: ScopeId, val: ValueRef, - ty: Ty<'tcx>) { + ty: Ty<'tcx>, + drop_hint: Option<DropHintDatum<'tcx>>) { if !self.type_needs_drop(ty) { return; } + let drop_hint = drop_hint.map(|hint|hint.to_value()); let drop = box DropValue { is_immediate: false, val: val, ty: ty, fill_on_drop: false, skip_dtor: false, + drop_hint: drop_hint, }; debug!("schedule_drop_mem({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}", @@ -413,23 +433,28 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { fn schedule_drop_and_fill_mem(&self, cleanup_scope: ScopeId, val: ValueRef, - ty: Ty<'tcx>) { + ty: Ty<'tcx>, + drop_hint: Option<DropHintDatum<'tcx>>) { if !self.type_needs_drop(ty) { return; } + let drop_hint = drop_hint.map(|datum|datum.to_value()); let drop = box DropValue { is_immediate: false, val: val, ty: ty, fill_on_drop: true, skip_dtor: false, + drop_hint: drop_hint, }; - debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={:?}, fill_on_drop={}, skip_dtor={})", + debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={:?}, + fill_on_drop={}, skip_dtor={}, has_drop_hint={})", cleanup_scope, self.ccx.tn().val_to_string(val), ty, drop.fill_on_drop, - drop.skip_dtor); + drop.skip_dtor, + drop_hint.is_some()); self.schedule_clean(cleanup_scope, drop as CleanupObj); } @@ -453,6 +478,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { ty: ty, fill_on_drop: false, skip_dtor: true, + drop_hint: None, }; debug!("schedule_drop_adt_contents({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}", @@ -472,13 +498,14 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { ty: Ty<'tcx>) { if !self.type_needs_drop(ty) { return; } - let drop = box DropValue { + let drop = Box::new(DropValue { is_immediate: true, val: val, ty: ty, fill_on_drop: false, skip_dtor: false, - }; + drop_hint: None, + }); debug!("schedule_drop_immediate({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}", cleanup_scope, @@ -983,6 +1010,7 @@ pub struct DropValue<'tcx> { ty: Ty<'tcx>, fill_on_drop: bool, skip_dtor: bool, + drop_hint: Option<DropHintValue>, } impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { @@ -1007,7 +1035,7 @@ impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { let bcx = if self.is_immediate { glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc, self.skip_dtor) } else { - glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor) + glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor, self.drop_hint) }; if self.fill_on_drop { base::drop_done_fill_mem(bcx, self.val, self.ty); @@ -1135,11 +1163,13 @@ pub trait CleanupMethods<'blk, 'tcx> { fn schedule_drop_mem(&self, cleanup_scope: ScopeId, val: ValueRef, - ty: Ty<'tcx>); + ty: Ty<'tcx>, + drop_hint: Option<DropHintDatum<'tcx>>); fn schedule_drop_and_fill_mem(&self, cleanup_scope: ScopeId, val: ValueRef, - ty: Ty<'tcx>); + ty: Ty<'tcx>, + drop_hint: Option<DropHintDatum<'tcx>>); fn schedule_drop_adt_contents(&self, cleanup_scope: ScopeId, val: ValueRef, diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index ef5da3e40df..d9787231096 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -82,9 +82,11 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr); if kind == ty::FnOnceClosureKind && !captured_by_ref { + let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id); bcx.fcx.schedule_drop_mem(arg_scope_id, upvar_ptr, - node_id_type(bcx, def_id.node)) + node_id_type(bcx, def_id.node), + hint) } if let Some(env_pointer_alloca) = env_pointer_alloca { diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 82c835e8c34..9478c197a44 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -318,6 +318,12 @@ pub struct DropFlagHintsMap<'tcx> { impl<'tcx> DropFlagHintsMap<'tcx> { pub fn new() -> DropFlagHintsMap<'tcx> { DropFlagHintsMap { node_map: NodeMap() } } pub fn has_hint(&self, id: ast::NodeId) -> bool { self.node_map.contains_key(&id) } + pub fn insert(&mut self, id: ast::NodeId, datum: cleanup::DropHintDatum<'tcx>) { + self.node_map.insert(id, HintEntry { datum: datum }); + } + pub fn hint_datum(&self, id: ast::NodeId) -> Option<cleanup::DropHintDatum<'tcx>> { + self.node_map.get(&id).map(|t|t.datum) + } } // Function context. Every LLVM function we create will have one of diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index f14b6f368f4..28fbc9fc8d5 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -93,11 +93,12 @@ pub use self::Expr::*; pub use self::RvalueMode::*; use llvm::ValueRef; +use trans::adt; use trans::base::*; -use trans::build::Load; +use trans::build::{Load, Store}; use trans::common::*; use trans::cleanup; -use trans::cleanup::CleanupMethods; +use trans::cleanup::{CleanupMethods, DropHintDatum, DropHintMethods}; use trans::expr; use trans::tvec; use trans::type_of; @@ -111,7 +112,7 @@ use syntax::codemap::DUMMY_SP; /// describes where the value is stored, what Rust type the value has, /// whether it is addressed by reference, and so forth. Please refer /// the section on datums in `README.md` for more details. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct Datum<'tcx, K> { /// The llvm value. This is either a pointer to the Rust value or /// the value itself, depending on `kind` below. @@ -141,7 +142,7 @@ pub enum Expr { LvalueExpr(Lvalue), } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum DropFlagInfo { DontZeroJustUse(ast::NodeId), ZeroAndMaintain(ast::NodeId), @@ -157,12 +158,18 @@ impl DropFlagInfo { } } - pub fn hint_to_maintain(&self) -> Option<ast::NodeId> { - match *self { - DropFlagInfo::DontZeroJustUse(id) => Some(id), - DropFlagInfo::ZeroAndMaintain(id) => Some(id), - DropFlagInfo::None => None, - } + pub fn hint_datum<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) + -> Option<DropHintDatum<'tcx>> { + let id = match *self { + DropFlagInfo::None => return None, + DropFlagInfo::DontZeroJustUse(id) | + DropFlagInfo::ZeroAndMaintain(id) => id, + }; + + let hints = bcx.fcx.lldropflag_hints.borrow(); + let retval = hints.hint_datum(id); + assert!(retval.is_some(), "An id (={}) means must have a hint", id); + retval } } @@ -182,7 +189,8 @@ pub struct Rvalue { pub mode: RvalueMode } -impl Lvalue { +// XXX: reduce this to a smaller kernel of constructors. +impl Lvalue { // These are all constructors for various Lvalues. pub fn new(source: &'static str) -> Lvalue { Lvalue { source: source, drop_flag_info: DropFlagInfo::None } } @@ -267,9 +275,21 @@ impl Lvalue { Lvalue { source: source, drop_flag_info: info } } + pub fn new_dropflag_hint(source: &'static str) -> Lvalue { + debug!("dropflag hint Lvalue at {}", source); + Lvalue { source: source, drop_flag_info: DropFlagInfo::None } + } +} // end Lvalue constructor methods. + +impl Lvalue { fn has_dropflag_hint<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, id: ast::NodeId) -> bool { - bcx.fcx.lldropflag_hints.borrow().has_hint(id) + let hints = bcx.fcx.lldropflag_hints.borrow(); + hints.has_hint(id) + } + pub fn dropflag_hint<'blk, 'tcx>(&self, bcx: Block<'blk, 'tcx>) + -> Option<DropHintDatum<'tcx>> { + self.drop_flag_info.hint_datum(bcx) } } @@ -323,7 +343,7 @@ pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, // Subtle. Populate the scratch memory *before* scheduling cleanup. let bcx = populate(arg, bcx, scratch); bcx.fcx.schedule_lifetime_end(scope, scratch); - bcx.fcx.schedule_drop_mem(scope, scratch, ty); + bcx.fcx.schedule_drop_mem(scope, scratch, ty, None); DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum"))) } @@ -362,7 +382,7 @@ fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode, ByValue => { fcx.schedule_drop_immediate(scope, val, ty); } ByRef => { fcx.schedule_lifetime_end(scope, val); - fcx.schedule_drop_mem(scope, val, ty); + fcx.schedule_drop_mem(scope, val, ty, None); } } } @@ -419,10 +439,28 @@ impl KindOps for Lvalue { -> Block<'blk, 'tcx> { let _icx = push_ctxt("<Lvalue as KindOps>::post_store"); if bcx.fcx.type_needs_drop(ty) { - // cancel cleanup of affine values by drop-filling the memory - let () = drop_done_fill_mem(bcx, val, ty); + // cancel cleanup of affine values: + // 1. if it has drop-hint, mark as moved; then code + // aware of drop-hint won't bother calling the + // drop-glue itself. + if let Some(hint_datum) = self.drop_flag_info.hint_datum(bcx) { + let moved_hint_byte = adt::DTOR_MOVED_HINT as usize; + let hint_llval = hint_datum.to_value().value(); + Store(bcx, C_u8(bcx.fcx.ccx, moved_hint_byte), hint_llval); + } + // 2. if the drop info says its necessary, drop-fill the memory. + if self.drop_flag_info.must_zero() { + let () = drop_done_fill_mem(bcx, val, ty); + } bcx } else { + // XXX would be nice to assert this, but we currently are + // adding e.g. DontZeroJustUse flags. (The dropflag hint + // construction should be taking !type_needs_drop into + // account; earlier analysis phases may not have all the + // info they need to do it properly, I think...) + // + // assert_eq!(self.drop_flag_info, DropFlagInfo::None); bcx } } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 1582a43d94d..ba0ae27a005 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -61,7 +61,7 @@ use middle::traits; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; use trans::base::*; use trans::build::*; -use trans::cleanup::{self, CleanupMethods}; +use trans::cleanup::{self, CleanupMethods, DropHintMethods}; use trans::common::*; use trans::datum::*; use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; @@ -1004,10 +1004,26 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); let src_datum = unpack_datum!( bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign")); - bcx = glue::drop_ty(bcx, - dst_datum.val, - dst_datum.ty, - expr.debug_loc()); + if let Some(hint_datum) = dst_datum.kind.drop_flag_info.hint_datum(bcx) { + let hint_val = hint_datum.to_value(); + // XXX the checkpointed branch only does the + // drop_ty call within this branch (and I claim + // that seems like a bug). At this point I have + // moved it into the branch solely to see if it + // makes my plague of bugs go away. + bcx = glue::drop_ty_core(bcx, + dst_datum.val, + dst_datum.ty, + expr.debug_loc(), + false, + Some(hint_val)); + // We are initializing or overwriting the + // destination, so we need to write "drop needed" + // into the hint. + let hint_llval = hint_val.value(); + let drop_needed = C_u8(bcx.fcx.ccx, adt::DTOR_NEEDED_HINT as usize); + Store(bcx, drop_needed, hint_llval); + } src_datum.store_to(bcx, dst_datum.val) } else { src_datum.store_to(bcx, dst_datum.val) @@ -1578,7 +1594,8 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, bcx = trans_into(bcx, &**e, SaveIn(dest)); let scope = cleanup::CustomScope(custom_cleanup_scope); fcx.schedule_lifetime_end(scope, dest); - fcx.schedule_drop_mem(scope, dest, e_ty); + // FIXME: nonzeroing move should generalize to fields + fcx.schedule_drop_mem(scope, dest, e_ty, None); } } diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index e530eb0de59..6019099c058 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -130,17 +130,20 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>, debug_loc: DebugLoc) -> Block<'blk, 'tcx> { - drop_ty_core(bcx, v, t, debug_loc, false) + drop_ty_core(bcx, v, t, debug_loc, false, None) } pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>, debug_loc: DebugLoc, - skip_dtor: bool) -> Block<'blk, 'tcx> { + skip_dtor: bool, + drop_hint: Option<cleanup::DropHintValue>) + -> Block<'blk, 'tcx> { // NB: v is an *alias* of type t here, not a direct value. - debug!("drop_ty_core(t={:?}, skip_dtor={})", t, skip_dtor); + debug!("drop_ty_core(t={:?}, skip_dtor={} drop_hint={:?})", t, skip_dtor, drop_hint); let _icx = push_ctxt("drop_ty"); + let mut bcx = bcx; if bcx.fcx.type_needs_drop(t) { let ccx = bcx.ccx(); let g = if skip_dtor { @@ -156,7 +159,23 @@ pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v }; - Call(bcx, glue, &[ptr], None, debug_loc); + match drop_hint { + Some(drop_hint) => { + let hint_val = load_ty(bcx, drop_hint.value(), bcx.tcx().types.u8); + let moved_val = + C_integral(Type::i8(bcx.ccx()), adt::DTOR_MOVED_HINT as u64, false); + let may_need_drop = + ICmp(bcx, llvm::IntNE, hint_val, moved_val, DebugLoc::None); + bcx = with_cond(bcx, may_need_drop, |cx| { + Call(cx, glue, &[ptr], None, debug_loc); + cx + }) + } + None => { + // No drop-hint ==> call standard drop glue + Call(bcx, glue, &[ptr], None, debug_loc); + } + } } bcx } @@ -170,7 +189,7 @@ pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("drop_ty_immediate"); let vp = alloca(bcx, type_of(bcx.ccx(), t), ""); store_ty(bcx, v, vp, t); - drop_ty_core(bcx, vp, t, debug_loc, skip_dtor) + drop_ty_core(bcx, vp, t, debug_loc, skip_dtor, None) } pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ValueRef { diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 0e05ca52959..a9abc61c274 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -117,7 +117,7 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Arrange for the backing array to be cleaned up. let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id); fcx.schedule_lifetime_end(cleanup_scope, llfixed); - fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty); + fcx.schedule_drop_mem(cleanup_scope, llfixed, fixed_ty, None); // Generate the content into the backing array. // llfixed has type *[T x N], but we want the type *T, @@ -212,7 +212,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, SaveIn(lleltptr)); let scope = cleanup::CustomScope(temp_scope); fcx.schedule_lifetime_end(scope, lleltptr); - fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty); + fcx.schedule_drop_mem(scope, lleltptr, vt.unit_ty, None); } fcx.pop_custom_cleanup_scope(temp_scope); } |
