introduce idea of "stealable" MIR

This is a more principled version of the `RefCell` we were using
before. We now allocate a `Steal<Mir<'tcx>>` for each intermediate MIR
pass; when the next pass steals the entry, any later attempts to use it
will panic (there is no way to *test* if MIR is stolen, you're just
supposed to *know*).
This commit is contained in:
Niko Matsakis 2017-04-28 06:00:48 -04:00
parent e89a321dff
commit 29263fdb54
12 changed files with 93 additions and 66 deletions

View file

@ -13,7 +13,7 @@ use hir::def_id::DefId;
use hir::map::DefPathData;
use mir::{Mir, Promoted};
use ty::TyCtxt;
use std::cell::{Ref, RefCell};
use std::cell::Ref;
use std::rc::Rc;
use syntax::ast::NodeId;
@ -98,7 +98,7 @@ pub trait MirCtxt<'a, 'tcx: 'a> {
fn pass_num(&self) -> MirPassIndex;
fn source(&self) -> MirSource;
fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>;
fn steal_previous_mir(&self) -> &'tcx RefCell<Mir<'tcx>>;
fn steal_previous_mir(&self) -> Mir<'tcx>;
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@ -132,7 +132,7 @@ pub trait DefIdPass {
default_name::<Self>()
}
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>>;
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx>;
}
/// A streamlined trait that you can implement to create a pass; the
@ -154,14 +154,14 @@ impl<T: MirPass> DefIdPass for T {
MirPass::name(self)
}
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>> {
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx> {
let tcx = mir_cx.tcx();
let source = mir_cx.source();
let mir = mir_cx.steal_previous_mir();
MirPass::run_pass(self, tcx, source, &mut mir.borrow_mut());
let mut mir = mir_cx.steal_previous_mir();
MirPass::run_pass(self, tcx, source, &mut mir);
let item_id = source.item_id();
for (promoted_index, promoted_mir) in mir.borrow_mut().promoted.iter_enumerated_mut() {
for (promoted_index, promoted_mir) in mir.promoted.iter_enumerated_mut() {
let promoted_source = MirSource::Promoted(item_id, promoted_index);
MirPass::run_pass(self, tcx, promoted_source, promoted_mir);
}

View file

@ -40,6 +40,7 @@ use ty::TypeVariants::*;
use ty::layout::{Layout, TargetDataLayout};
use ty::inhabitedness::DefIdForest;
use ty::maps;
use ty::steal::Steal;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec;
@ -70,7 +71,8 @@ pub struct GlobalArenas<'tcx> {
generics: TypedArena<ty::Generics>,
trait_def: TypedArena<ty::TraitDef>,
adt_def: TypedArena<ty::AdtDef>,
mir: TypedArena<RefCell<Mir<'tcx>>>,
steal_mir: TypedArena<Steal<Mir<'tcx>>>,
mir: TypedArena<Mir<'tcx>>,
tables: TypedArena<ty::TypeckTables<'tcx>>,
}
@ -81,6 +83,7 @@ impl<'tcx> GlobalArenas<'tcx> {
generics: TypedArena::new(),
trait_def: TypedArena::new(),
adt_def: TypedArena::new(),
steal_mir: TypedArena::new(),
mir: TypedArena::new(),
tables: TypedArena::new(),
}
@ -622,8 +625,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.global_arenas.generics.alloc(generics)
}
pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx RefCell<Mir<'gcx>> {
self.global_arenas.mir.alloc(RefCell::new(mir))
pub fn alloc_steal_mir(self, mir: Mir<'gcx>) -> &'gcx Steal<Mir<'gcx>> {
self.global_arenas.steal_mir.alloc(Steal::new(mir))
}
pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx Mir<'gcx> {
self.global_arenas.mir.alloc(mir)
}
pub fn alloc_tables(self, tables: ty::TypeckTables<'gcx>) -> &'gcx ty::TypeckTables<'gcx> {

View file

@ -20,6 +20,7 @@ use mir::transform::{MirSuite, MirPassIndex};
use session::CompileResult;
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use ty::item_path;
use ty::steal::Steal;
use ty::subst::Substs;
use util::nodemap::{DefIdSet, NodeSet};
@ -32,7 +33,7 @@ use std::rc::Rc;
use syntax_pos::{Span, DUMMY_SP};
use syntax::symbol::Symbol;
trait Key {
trait Key: Clone {
fn map_crate(&self) -> CrateNum;
fn default_span(&self, tcx: TyCtxt) -> Span;
}
@ -339,13 +340,13 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> {
impl<'tcx> QueryDescription for queries::mir_suite<'tcx> {
fn describe(_: TyCtxt, (suite, _): (MirSuite, DefId)) -> String {
format!("MIR passes #{}.*", suite.0)
format!("MIR suite #{}.*", suite.0)
}
}
impl<'tcx> QueryDescription for queries::mir_pass<'tcx> {
fn describe(_: TyCtxt, (pass_set, pass_num, _): (MirSuite, MirPassIndex, DefId)) -> String {
format!("MIR pass #{}.{}", pass_set.0, pass_num.0)
fn describe(_: TyCtxt, (suite, pass_num, _): (MirSuite, MirPassIndex, DefId)) -> String {
format!("MIR pass #{}.{}", suite.0, pass_num.0)
}
}
@ -586,22 +587,22 @@ define_maps! { <'tcx>
/// Performs the initial MIR construction. You almost certainly do not
/// want to use this query, because its output is intended to be stolen
/// immediately by the MIR passes below. Consider `optimized_mir` instead.
[] mir_build: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
[] mir_build: Mir(DefId) -> &'tcx Steal<mir::Mir<'tcx>>,
/// Fetch the MIR for a given def-id after the given set of passes has ben
/// applied to it. This is mostly an "intermediate" query. Normally, you would
/// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all
/// optimizations and so forth.
[] mir_suite: mir_suite((MirSuite, DefId)) -> &'tcx RefCell<mir::Mir<'tcx>>,
[] mir_suite: mir_suite((MirSuite, DefId)) -> &'tcx Steal<mir::Mir<'tcx>>,
/// Fetch the MIR for a given def-id after a given pass has been executed. This is
/// **only** intended to be used by the `mir_suite` provider -- if you are using it
/// manually, you're doing it wrong.
[] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx RefCell<mir::Mir<'tcx>>,
[] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal<mir::Mir<'tcx>>,
/// MIR after our optimization passes have run. This is MIR that is ready
/// for trans. This is also the only query that can fetch non-local MIR, at present.
[] optimized_mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
[] optimized_mir: Mir(DefId) -> &'tcx mir::Mir<'tcx>,
/// Records the type of each closure. The def ID is the ID of the
/// expression defining the closure.
@ -650,7 +651,7 @@ define_maps! { <'tcx>
/// fn item.
[] region_maps: RegionMaps(DefId) -> Rc<RegionMaps<'tcx>>,
[] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>,
[] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>,
[] def_symbol_name: SymbolName(DefId) -> ty::SymbolName,
[] symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName,

View file

@ -35,7 +35,7 @@ use util::common::ErrorReported;
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
use serialize::{self, Encodable, Encoder};
use std::cell::{Cell, RefCell, Ref};
use std::cell::{Cell, RefCell};
use std::collections::BTreeMap;
use std::cmp;
use std::fmt;
@ -96,6 +96,7 @@ pub mod _match;
pub mod maps;
pub mod outlives;
pub mod relate;
pub mod steal;
pub mod subst;
pub mod trait_def;
pub mod walk;
@ -2324,13 +2325,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
/// Given the did of an item, returns its (optimized) MIR, borrowed immutably.
pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
self.optimized_mir(did).borrow()
pub fn item_mir(self, did: DefId) -> &'gcx Mir<'gcx> {
self.optimized_mir(did)
}
/// Return the possibly-auto-generated MIR of a (DefId, Subst) pair.
pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>)
-> Ref<'gcx, Mir<'gcx>>
-> &'gcx Mir<'gcx>
{
match instance {
ty::InstanceDef::Item(did) => {
@ -2341,14 +2342,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::InstanceDef::Virtual(..) |
ty::InstanceDef::ClosureOnceShim { .. } |
ty::InstanceDef::DropGlue(..) => {
self.mir_shims(instance).borrow()
self.mir_shims(instance)
}
}
}
/// Given the DefId of an item, returns its MIR, borrowed immutably.
/// Returns None if there is no MIR for the DefId
pub fn maybe_item_mir(self, did: DefId) -> Option<Ref<'gcx, Mir<'gcx>>> {
pub fn maybe_item_mir(self, did: DefId) -> Option<&'gcx Mir<'gcx>> {
if did.is_local() && !self.mir_keys(LOCAL_CRATE).contains(&did) {
return None;
}

27
src/librustc/ty/steal.rs Normal file
View file

@ -0,0 +1,27 @@
use std::cell::{Ref, RefCell};
use std::mem;
pub struct Steal<T> {
value: RefCell<Option<T>>
}
impl<T> Steal<T> {
pub fn new(value: T) -> Self {
Steal {
value: RefCell::new(Some(value))
}
}
pub fn borrow(&self) -> Ref<T> {
Ref::map(self.value.borrow(), |opt| match *opt {
None => panic!("attempted to read from stolen value"),
Some(ref v) => v
})
}
pub fn steal(&self) -> T {
let value_ref = &mut *self.value.borrow_mut();
let value = mem::replace(value_ref, None);
value.expect("attempt to read from stolen value")
}
}