Skip to content

Commit d5a5149

Browse files
Move caching of HIR-inlining into CStore in order to avoid duplicating inlined HIR.
1 parent 535cea0 commit d5a5149

File tree

17 files changed

+335
-175
lines changed

17 files changed

+335
-175
lines changed

src/librustc/hir/intravisit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) {
867867
}
868868
}
869869

870-
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)]
870+
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)]
871871
pub struct IdRange {
872872
pub min: NodeId,
873873
pub max: NodeId,
@@ -893,6 +893,7 @@ impl IdRange {
893893
self.min = cmp::min(self.min, id);
894894
self.max = cmp::max(self.max, id + 1);
895895
}
896+
896897
}
897898

898899

src/librustc/hir/map/mod.rs

+57-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use hir::print as pprust;
3232

3333
use arena::TypedArena;
3434
use std::cell::RefCell;
35+
use std::cmp;
3536
use std::io;
3637
use std::mem;
3738

@@ -127,7 +128,10 @@ impl<'ast> MapEntry<'ast> {
127128
EntryStructCtor(id, _) => id,
128129
EntryLifetime(id, _) => id,
129130
EntryTyParam(id, _) => id,
130-
_ => return None
131+
132+
NotPresent |
133+
RootCrate |
134+
RootInlinedParent(_) => return None,
131135
})
132136
}
133137

@@ -196,6 +200,10 @@ pub struct Map<'ast> {
196200
map: RefCell<Vec<MapEntry<'ast>>>,
197201

198202
definitions: RefCell<Definitions>,
203+
204+
/// All NodeIds that are numerically greater or equal to this value come
205+
/// from inlined items.
206+
local_node_id_watermark: NodeId,
199207
}
200208

201209
impl<'ast> Map<'ast> {
@@ -550,6 +558,13 @@ impl<'ast> Map<'ast> {
550558
}
551559
}
552560

561+
pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem {
562+
match self.find_entry(id) {
563+
Some(RootInlinedParent(inlined_item)) => inlined_item,
564+
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
565+
}
566+
}
567+
553568
/// Returns the name associated with the given NodeId's AST.
554569
pub fn name(&self, id: NodeId) -> Name {
555570
match self.get(id) {
@@ -649,6 +664,10 @@ impl<'ast> Map<'ast> {
649664
pub fn node_to_user_string(&self, id: NodeId) -> String {
650665
node_id_to_string(self, id, false)
651666
}
667+
668+
pub fn is_inlined(&self, id: NodeId) -> bool {
669+
id >= self.local_node_id_watermark
670+
}
652671
}
653672

654673
pub struct NodesMatchingSuffix<'a, 'ast:'a> {
@@ -765,13 +784,37 @@ pub trait FoldOps {
765784
}
766785

767786
/// A Folder that updates IDs and Span's according to fold_ops.
768-
struct IdAndSpanUpdater<F> {
769-
fold_ops: F
787+
pub struct IdAndSpanUpdater<F> {
788+
fold_ops: F,
789+
min_id_assigned: NodeId,
790+
max_id_assigned: NodeId,
791+
}
792+
793+
impl<F: FoldOps> IdAndSpanUpdater<F> {
794+
pub fn new(fold_ops: F) -> IdAndSpanUpdater<F> {
795+
IdAndSpanUpdater {
796+
fold_ops: fold_ops,
797+
min_id_assigned: ::std::u32::MAX,
798+
max_id_assigned: ::std::u32::MIN,
799+
}
800+
}
801+
802+
pub fn id_range(&self) -> intravisit::IdRange {
803+
intravisit::IdRange {
804+
min: self.min_id_assigned,
805+
max: self.max_id_assigned + 1,
806+
}
807+
}
770808
}
771809

772810
impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
773811
fn new_id(&mut self, id: NodeId) -> NodeId {
774-
self.fold_ops.new_id(id)
812+
let id = self.fold_ops.new_id(id);
813+
814+
self.min_id_assigned = cmp::min(self.min_id_assigned, id);
815+
self.max_id_assigned = cmp::max(self.max_id_assigned, id);
816+
817+
id
775818
}
776819

777820
fn new_span(&mut self, span: Span) -> Span {
@@ -802,11 +845,14 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
802845
entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
803846
}
804847

848+
let local_node_id_watermark = map.len() as NodeId;
849+
805850
Map {
806851
forest: forest,
807852
dep_graph: forest.dep_graph.clone(),
808853
map: RefCell::new(map),
809854
definitions: RefCell::new(definitions),
855+
local_node_id_watermark: local_node_id_watermark
810856
}
811857
}
812858

@@ -818,7 +864,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
818864
ii: InlinedItem,
819865
fold_ops: F)
820866
-> &'ast InlinedItem {
821-
let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
867+
let mut fld = IdAndSpanUpdater::new(fold_ops);
822868
let ii = match ii {
823869
II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))),
824870
II::TraitItem(d, ti) => {
@@ -835,6 +881,12 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
835881
let ii = map.forest.inlined_items.alloc(ii);
836882
let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
837883

884+
// Assert that the ii_parent_id is the last NodeId in our reserved range
885+
assert!(ii_parent_id == fld.max_id_assigned);
886+
// Assert that we did not violate the invariant that all inlined HIR items
887+
// have NodeIds greater than or equal to `local_node_id_watermark`
888+
assert!(fld.min_id_assigned >= map.local_node_id_watermark);
889+
838890
let defs = &mut *map.definitions.borrow_mut();
839891
let mut def_collector = DefCollector::extend(ii_parent_id,
840892
parent_def_path.clone(),

src/librustc/middle/cstore.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,6 @@ pub struct ChildItem {
120120
pub vis: ty::Visibility,
121121
}
122122

123-
pub enum FoundAst<'ast> {
124-
Found(&'ast InlinedItem),
125-
FoundParent(DefId, &'ast hir::Item),
126-
NotFound,
127-
}
128-
129123
#[derive(Copy, Clone, Debug)]
130124
pub struct ExternCrate {
131125
/// def_id of an `extern crate` in the current crate that caused
@@ -250,7 +244,10 @@ pub trait CrateStore<'tcx> {
250244

251245
// misc. metadata
252246
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
253-
-> FoundAst<'tcx>;
247+
-> Option<(&'tcx InlinedItem, ast::NodeId)>;
248+
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
249+
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
250+
254251
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
255252
-> Option<Mir<'tcx>>;
256253
fn is_item_mir_available(&self, def: DefId) -> bool;
@@ -447,7 +444,16 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
447444

448445
// misc. metadata
449446
fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
450-
-> FoundAst<'tcx> { bug!("maybe_get_item_ast") }
447+
-> Option<(&'tcx InlinedItem, ast::NodeId)> {
448+
bug!("maybe_get_item_ast")
449+
}
450+
fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
451+
bug!("local_node_for_inlined_defid")
452+
}
453+
fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
454+
bug!("defid_for_inlined_node")
455+
}
456+
451457
fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
452458
-> Option<Mir<'tcx>> { bug!("maybe_get_item_mir") }
453459
fn is_item_mir_available(&self, def: DefId) -> bool {

src/librustc_const_eval/eval.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use self::EvalHint::*;
1717

1818
use rustc::hir::map as ast_map;
1919
use rustc::hir::map::blocks::FnLikeNode;
20-
use rustc::middle::cstore::{self, InlinedItem};
20+
use rustc::middle::cstore::InlinedItem;
2121
use rustc::traits;
2222
use rustc::hir::def::{Def, PathResolution};
2323
use rustc::hir::def_id::DefId;
@@ -142,13 +142,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
142142
}
143143
let mut used_substs = false;
144144
let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
145-
cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
145+
Some((&InlinedItem::Item(ref item), _)) => match item.node {
146146
hir::ItemConst(ref ty, ref const_expr) => {
147147
Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
148148
},
149149
_ => None
150150
},
151-
cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node {
151+
Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
152152
hir::ConstTraitItem(_, _) => {
153153
used_substs = true;
154154
if let Some(substs) = substs {
@@ -163,7 +163,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
163163
}
164164
_ => None
165165
},
166-
cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node {
166+
Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node {
167167
hir::ImplItemKind::Const(ref ty, ref expr) => {
168168
Some((&**expr, tcx.ast_ty_to_prim_ty(ty)))
169169
},
@@ -198,8 +198,8 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
198198
}
199199

200200
let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
201-
cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id),
202-
cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id),
201+
Some((&InlinedItem::Item(ref item), _)) => Some(item.id),
202+
Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
203203
_ => None
204204
};
205205
tcx.extern_const_fns.borrow_mut().insert(def_id,

src/librustc_metadata/astencode.rs

+42-9
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext,
8888
rbml_w.writer.seek(SeekFrom::Current(0)));
8989

9090
// Folding could be avoided with a smarter encoder.
91-
let ii = simplify_ast(ii);
91+
let (ii, expected_id_range) = simplify_ast(ii);
9292
let id_range = inlined_item_id_range(&ii);
93+
assert_eq!(expected_id_range, id_range);
9394

9495
rbml_w.start_tag(c::tag_ast as usize);
9596
id_range.encode(rbml_w);
@@ -186,6 +187,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> {
186187
pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId {
187188
// from_id_range should be non-empty
188189
assert!(!self.from_id_range.empty());
190+
// Make sure that translating the NodeId will actually yield a
191+
// meaningful result
192+
assert!(self.from_id_range.contains(id));
193+
189194
// Use wrapping arithmetic because otherwise it introduces control flow.
190195
// Maybe we should just have the control flow? -- aatch
191196
(id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min))
@@ -279,9 +284,23 @@ fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) {
279284
rbml_w.end_tag();
280285
}
281286

282-
struct NestedItemsDropper;
287+
struct NestedItemsDropper {
288+
id_range: IdRange
289+
}
283290

284291
impl Folder for NestedItemsDropper {
292+
293+
// The unit tests below run on HIR with NodeIds not properly assigned. That
294+
// causes an integer overflow. So we just don't track the id_range when
295+
// building the unit tests.
296+
#[cfg(not(test))]
297+
fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId {
298+
// Record the range of NodeIds we are visiting, so we can do a sanity
299+
// check later
300+
self.id_range.add(id);
301+
id
302+
}
303+
285304
fn fold_block(&mut self, blk: P<hir::Block>) -> P<hir::Block> {
286305
blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| {
287306
let stmts_sans_items = stmts.into_iter().filter_map(|stmt| {
@@ -322,10 +341,12 @@ impl Folder for NestedItemsDropper {
322341
// As it happens, trans relies on the fact that we do not export
323342
// nested items, as otherwise it would get confused when translating
324343
// inlined items.
325-
fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
326-
let mut fld = NestedItemsDropper;
344+
fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) {
345+
let mut fld = NestedItemsDropper {
346+
id_range: IdRange::max()
347+
};
327348

328-
match ii {
349+
let ii = match ii {
329350
// HACK we're not dropping items.
330351
InlinedItemRef::Item(i) => {
331352
InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld)))
@@ -339,7 +360,9 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
339360
InlinedItemRef::Foreign(i) => {
340361
InlinedItem::Foreign(P(fold::noop_fold_foreign_item(i.clone(), &mut fld)))
341362
}
342-
}
363+
};
364+
365+
(ii, fld.id_range)
343366
}
344367

345368
fn decode_ast(item_doc: rbml::Doc) -> InlinedItem {
@@ -361,8 +384,18 @@ impl tr for Def {
361384
match *self {
362385
Def::Fn(did) => Def::Fn(did.tr(dcx)),
363386
Def::Method(did) => Def::Method(did.tr(dcx)),
364-
Def::SelfTy(opt_did, impl_id) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
365-
impl_id.map(|id| dcx.tr_id(id))) }
387+
Def::SelfTy(opt_did, impl_id) => {
388+
// Since the impl_id will never lie within the reserved range of
389+
// imported NodeIds, it does not make sense to translate it.
390+
// The result would not make any sense within the importing crate.
391+
// We also don't allow for impl items to be inlined (just their
392+
// members), so even if we had a DefId here, we wouldn't be able
393+
// to do much with it.
394+
// So, we set the id to DUMMY_NODE_ID. That way we make it
395+
// explicit that this is no usable NodeId.
396+
Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
397+
impl_id.map(|_| ast::DUMMY_NODE_ID))
398+
}
366399
Def::Mod(did) => { Def::Mod(did.tr(dcx)) }
367400
Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) }
368401
Def::Static(did, m) => { Def::Static(did.tr(dcx), m) }
@@ -1361,7 +1394,7 @@ fn test_simplification() {
13611394
with_testing_context(|lcx| {
13621395
let hir_item = lcx.lower_item(&item);
13631396
let item_in = InlinedItemRef::Item(&hir_item);
1364-
let item_out = simplify_ast(item_in);
1397+
let (item_out, _) = simplify_ast(item_in);
13651398
let item_exp = InlinedItem::Item(P(lcx.lower_item(&quote_item!(&cx,
13661399
fn new_int_alist<B>() -> alist<isize, B> {
13671400
return alist {eq_fn: eq_int, data: Vec::new()};

0 commit comments

Comments
 (0)