diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs new file mode 100644 index 00000000000..23493d5c93f --- /dev/null +++ b/src/librustc/arena.rs @@ -0,0 +1,94 @@ +use arena::{TypedArena, DroplessArena}; + +#[macro_export] +macro_rules! arena_types { + ($macro:path, $args:tt, $tcx:lifetime) => ( + $macro!($args, [ + [] vtable_method: Option<( + rustc::hir::def_id::DefId, + rustc::ty::subst::SubstsRef<$tcx> + )>, + [decode] specialization_graph: rustc::traits::specialization_graph::Graph, + ], $tcx); + ) +} + +macro_rules! declare_arena { + ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + #[derive(Default)] + pub struct Arena<$tcx> { + dropless: DroplessArena, + $($name: TypedArena<$ty>,)* + } + } +} + +macro_rules! impl_specialized_decodable { + ([decode] $ty:ty, $tcx:lifetime) => { + impl<$tcx> serialize::UseSpecializedDecodable for &$tcx $ty {} + }; + ([] $ty:ty, $tcx:lifetime) => {}; +} + +macro_rules! impl_arena_allocatable { + ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + $( + impl_specialized_decodable!($a $ty, $tcx); + + impl<$tcx> ArenaAllocatable<$tcx> for $ty { + #[inline] + fn arena<'a>(arena: &'a Arena<$tcx>) -> Option<&'a TypedArena> { + Some(&arena.$name) + } + } + )* + } +} + +arena_types!(declare_arena, [], 'tcx); + +arena_types!(impl_arena_allocatable, [], 'tcx); + +pub trait ArenaAllocatable<'tcx>: Sized { + /// Returns a specific arena to allocate from if the type requires destructors. + /// Otherwise it will return `None` to be allocated from the dropless arena. + fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a TypedArena>; +} + +impl<'tcx, T: Copy> ArenaAllocatable<'tcx> for T { + #[inline] + default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a TypedArena> { + None + } +} + +impl<'tcx> Arena<'tcx> { + #[inline] + pub fn alloc>(&self, value: T) -> &mut T { + match T::arena(self) { + Some(arena) => { + arena.alloc(value) + } + None => { + self.dropless.alloc(value) + } + } + } + + pub fn alloc_from_iter< + T: ArenaAllocatable<'tcx>, + I: IntoIterator + >( + &self, + iter: I + ) -> &mut [T] { + match T::arena(self) { + Some(arena) => { + arena.alloc_from_iter(iter) + } + None => { + self.dropless.alloc_from_iter(iter) + } + } + } +} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 0b75cb6c8a3..ab44efa5dec 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -103,6 +103,8 @@ pub mod diagnostics; #[macro_use] pub mod query; +#[macro_use] +pub mod arena; pub mod cfg; pub mod dep_graph; pub mod hir; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 8896f9f9728..a62a2939544 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -516,7 +516,7 @@ rustc_queries! { Other { query vtable_methods(key: ty::PolyTraitRef<'tcx>) - -> Lrc)>>> { + -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { no_force desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } } @@ -539,8 +539,7 @@ rustc_queries! { query trait_impls_of(key: DefId) -> Lrc { desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) } } - query specialization_graph_of(_: DefId) - -> Lrc {} + query specialization_graph_of(_: DefId) -> &'tcx specialization_graph::Graph {} query is_object_safe(key: DefId) -> bool { desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 78c80b48ee8..d91c08b070a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -26,7 +26,6 @@ use crate::infer::{InferCtxt, SuppressRegionErrors}; use crate::infer::outlives::env::OutlivesEnvironment; use crate::middle::region; use crate::mir::interpret::ErrorHandled; -use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -984,11 +983,11 @@ fn substitute_normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx fn vtable_methods<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) - -> Lrc)>>> + -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { debug!("vtable_methods({:?})", trait_ref); - Lrc::new( + tcx.arena.alloc_from_iter( supertraits(tcx, trait_ref).flat_map(move |trait_ref| { let trait_methods = tcx.associated_items(trait_ref.def_id()) .filter(|item| item.kind == ty::AssociatedKind::Method); @@ -1039,7 +1038,7 @@ fn vtable_methods<'a, 'tcx>( Some((def_id, substs)) }) - }).collect() + }) ) } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index c576586fcad..384a5862cde 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -16,7 +16,6 @@ use crate::infer::{InferCtxt, InferOk}; use crate::lint; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; use syntax_pos::DUMMY_SP; use crate::traits::select::IntercrateAmbiguityCause; use crate::ty::{self, TyCtxt, TypeFoldable}; @@ -289,7 +288,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, pub(super) fn specialization_graph_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_id: DefId, -) -> Lrc { +) -> &'tcx specialization_graph::Graph { let mut sg = specialization_graph::Graph::new(); let mut trait_impls = tcx.all_impls(trait_id); @@ -383,7 +382,7 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>( } } - Lrc::new(sg) + tcx.arena.alloc(sg) } /// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 561859c7c31..dae1518d722 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -7,7 +7,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, use crate::traits; use crate::ty::{self, TyCtxt, TypeFoldable}; use crate::ty::fast_reject::{self, SimplifiedType}; -use rustc_data_structures::sync::Lrc; use syntax::ast::Ident; use crate::util::captures::Captures; use crate::util::nodemap::{DefIdMap, FxHashMap}; @@ -439,13 +438,13 @@ impl<'a, 'gcx, 'tcx> Node { } } -pub struct Ancestors { +pub struct Ancestors<'tcx> { trait_def_id: DefId, - specialization_graph: Lrc, + specialization_graph: &'tcx Graph, current_source: Option, } -impl Iterator for Ancestors { +impl Iterator for Ancestors<'_> { type Item = Node; fn next(&mut self) -> Option { let cur = self.current_source.take(); @@ -476,7 +475,7 @@ impl NodeItem { } } -impl<'a, 'gcx, 'tcx> Ancestors { +impl<'a, 'gcx, 'tcx> Ancestors<'gcx> { /// Search the items from the given ancestors, returning each definition /// with the given name and the given kind. // FIXME(#35870): avoid closures being unexported due to `impl Trait`. @@ -509,10 +508,10 @@ impl<'a, 'gcx, 'tcx> Ancestors { /// Walk up the specialization ancestors of a given impl, starting with that /// impl itself. -pub fn ancestors(tcx: TyCtxt<'_, '_, '_>, +pub fn ancestors(tcx: TyCtxt<'_, 'tcx, '_>, trait_def_id: DefId, start_from_impl: DefId) - -> Ancestors { + -> Ancestors<'tcx> { let specialization_graph = tcx.specialization_graph_of(trait_def_id); Ancestors { trait_def_id, diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index e7474345c00..038cd9812e7 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -6,6 +6,7 @@ // The functionality in here is shared between persisting to crate metadata and // persisting to incr. comp. caches. +use crate::arena::ArenaAllocatable; use crate::hir::def_id::{DefId, CrateNum}; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use rustc_data_structures::fx::FxHashMap; @@ -130,6 +131,26 @@ pub trait TyDecoder<'a, 'tcx: 'a>: Decoder { } } +#[inline] +pub fn decode_arena_allocable<'a, 'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>( + decoder: &mut D +) -> Result<&'tcx T, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().arena.alloc(Decodable::decode(decoder)?)) +} + +#[inline] +pub fn decode_arena_allocable_slice<'a, 'tcx, D, T: ArenaAllocatable<'tcx> + Decodable>( + decoder: &mut D +) -> Result<&'tcx [T], D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().arena.alloc_from_iter( as Decodable>::decode(decoder)?)) +} + #[inline] pub fn decode_cnum<'a, 'tcx, D>(decoder: &mut D) -> Result where D: TyDecoder<'a, 'tcx>, @@ -273,6 +294,35 @@ macro_rules! __impl_decoder_methods { } } +#[macro_export] +macro_rules! impl_arena_allocatable_decoder { + ([$DecoderName:ident [$($typaram:tt),*]], [[decode] $name:ident: $ty:ty], $tcx:lifetime) => { + impl<$($typaram),*> SpecializedDecoder<&$tcx $ty> for $DecoderName<$($typaram),*> { + #[inline] + fn specialized_decode(&mut self) -> Result<&$tcx $ty, Self::Error> { + decode_arena_allocable(self) + } + } + + impl<$($typaram),*> SpecializedDecoder<&$tcx [$ty]> for $DecoderName<$($typaram),*> { + #[inline] + fn specialized_decode(&mut self) -> Result<&$tcx [$ty], Self::Error> { + decode_arena_allocable_slice(self) + } + } + }; + ([$DecoderName:ident [$($typaram:tt),*]], [[] $name:ident: $ty:ty], $tcx:lifetime) => {}; +} + +#[macro_export] +macro_rules! impl_arena_allocatable_decoders { + ($args:tt, [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + $( + impl_arena_allocatable_decoder!($args, [$a $name: $ty], $tcx); + )* + } +} + #[macro_export] macro_rules! implement_ty_decoder { ($DecoderName:ident <$($typaram:tt),*>) => { @@ -322,6 +372,8 @@ macro_rules! implement_ty_decoder { // the caller to pick any lifetime for 'tcx, including 'static, // by using the unspecialized proxies to them. + arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); + impl<$($typaram),*> SpecializedDecoder for $DecoderName<$($typaram),*> { fn specialized_decode(&mut self) -> Result { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index aa5610739fd..7dc4dee3fbf 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1,5 +1,6 @@ //! Type context book-keeping. +use crate::arena::Arena; use crate::dep_graph::DepGraph; use crate::dep_graph::{self, DepNode, DepConstructor}; use crate::session::Session; @@ -1003,6 +1004,7 @@ impl<'gcx> Deref for TyCtxt<'_, 'gcx, '_> { } pub struct GlobalCtxt<'tcx> { + pub arena: WorkerLocal>, global_arenas: &'tcx WorkerLocal>, global_interners: CtxtInterners<'tcx>, @@ -1262,6 +1264,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { GlobalCtxt { sess: s, cstore, + arena: WorkerLocal::new(|_| Arena::default()), global_arenas: &arenas.global, global_interners: interners, dep_graph, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 143b5bf3762..58f21893de1 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> TraitDef { pub fn ancestors(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, of_impl: DefId) - -> specialization_graph::Ancestors { + -> specialization_graph::Ancestors<'gcx> { specialization_graph::ancestors(tcx, self.def_id, of_impl) } } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index cce6c95a312..5cfe7c496f5 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::sync::Lrc; use rustc::ty::{self, Ty}; use rustc::ty::layout::{Size, Align, LayoutOf}; use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic}; @@ -35,7 +34,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> self.tcx.vtable_methods(trait_ref) } else { - Lrc::new(Vec::new()) + &[] }; let layout = self.layout_of(ty)?; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index cf948078b08..234435f40a0 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -911,4 +911,4 @@ impl Decodable for T { impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {} impl UseSpecializedEncodable for Box {} impl UseSpecializedDecodable for Box {} - +impl<'a, T: ?Sized + Decodable> UseSpecializedDecodable for &'a [T] {}