]> git.lizzy.rs Git - rust.git/blob - src/librustc/arena.rs
Rollup merge of #59128 - oli-obk:colorful_json, r=mark-i-m,eddyb
[rust.git] / src / librustc / arena.rs
1 use arena::{TypedArena, DroplessArena};
2 use std::mem;
3 use std::ptr;
4 use std::slice;
5 use std::cell::RefCell;
6 use std::marker::PhantomData;
7 use smallvec::SmallVec;
8
9 #[macro_export]
10 macro_rules! arena_types {
11     ($macro:path, $args:tt, $tcx:lifetime) => (
12         $macro!($args, [
13             [] vtable_method: Option<(
14                 rustc::hir::def_id::DefId,
15                 rustc::ty::subst::SubstsRef<$tcx>
16             )>,
17             [few] mir_keys: rustc::util::nodemap::DefIdSet,
18             [decode] specialization_graph: rustc::traits::specialization_graph::Graph,
19         ], $tcx);
20     )
21 }
22
23 macro_rules! arena_for_type {
24     ([][$ty:ty]) => {
25         TypedArena<$ty>
26     };
27     ([few $(, $attrs:ident)*][$ty:ty]) => {
28         PhantomData<$ty>
29     };
30     ([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
31         arena_for_type!([$($attrs),*]$args)
32     };
33 }
34
35 macro_rules! declare_arena {
36     ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
37         #[derive(Default)]
38         pub struct Arena<$tcx> {
39             dropless: DroplessArena,
40             drop: DropArena,
41             $($name: arena_for_type!($a[$ty]),)*
42         }
43     }
44 }
45
46 macro_rules! which_arena_for_type {
47     ([][$arena:expr]) => {
48         Some($arena)
49     };
50     ([few$(, $attrs:ident)*][$arena:expr]) => {
51         None
52     };
53     ([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
54         which_arena_for_type!([$($attrs),*]$args)
55     };
56 }
57
58 macro_rules! impl_arena_allocatable {
59     ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
60         $(
61             impl ArenaAllocatable for $ty {}
62             unsafe impl<$tcx> ArenaField<$tcx> for $ty {
63                 #[inline]
64                 fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a TypedArena<Self>> {
65                     which_arena_for_type!($a[&_arena.$name])
66                 }
67             }
68         )*
69     }
70 }
71
72 arena_types!(declare_arena, [], 'tcx);
73
74 arena_types!(impl_arena_allocatable, [], 'tcx);
75
76 pub trait ArenaAllocatable {}
77
78 impl<T: Copy> ArenaAllocatable for T {}
79
80 pub unsafe trait ArenaField<'tcx>: Sized {
81     /// Returns a specific arena to allocate from.
82     /// If None is returned, the DropArena will be used.
83     fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>>;
84 }
85
86 unsafe impl<'tcx, T> ArenaField<'tcx> for T {
87     #[inline]
88     default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>> {
89         panic!()
90     }
91 }
92
93 impl<'tcx> Arena<'tcx> {
94     #[inline]
95     pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T {
96         if !mem::needs_drop::<T>() {
97             return self.dropless.alloc(value);
98         }
99         match <T as ArenaField<'tcx>>::arena(self) {
100             Some(arena) => arena.alloc(value),
101             None => unsafe { self.drop.alloc(value) },
102         }
103     }
104
105     pub fn alloc_from_iter<
106         T: ArenaAllocatable,
107         I: IntoIterator<Item = T>
108     >(
109         &'a self,
110         iter: I
111     ) -> &'a mut [T] {
112         if !mem::needs_drop::<T>() {
113             return self.dropless.alloc_from_iter(iter);
114         }
115         match <T as ArenaField<'tcx>>::arena(self) {
116             Some(arena) => arena.alloc_from_iter(iter),
117             None => unsafe { self.drop.alloc_from_iter(iter) },
118         }
119     }
120 }
121
122 /// Calls the destructor for an object when dropped.
123 struct DropType {
124     drop_fn: unsafe fn(*mut u8),
125     obj: *mut u8,
126 }
127
128 unsafe fn drop_for_type<T>(to_drop: *mut u8) {
129     std::ptr::drop_in_place(to_drop as *mut T)
130 }
131
132 impl Drop for DropType {
133     fn drop(&mut self) {
134         unsafe {
135             (self.drop_fn)(self.obj)
136         }
137     }
138 }
139
140 /// An arena which can be used to allocate any type.
141 /// Allocating in this arena is unsafe since the type system
142 /// doesn't know which types it contains. In order to
143 /// allocate safely, you must store a PhantomData<T>
144 /// alongside this arena for each type T you allocate.
145 #[derive(Default)]
146 struct DropArena {
147     /// A list of destructors to run when the arena drops.
148     /// Ordered so `destructors` gets dropped before the arena
149     /// since its destructor can reference memory in the arena.
150     destructors: RefCell<Vec<DropType>>,
151     arena: DroplessArena,
152 }
153
154 impl DropArena {
155     #[inline]
156     unsafe fn alloc<T>(&self, object: T) -> &mut T {
157         let mem = self.arena.alloc_raw(
158             mem::size_of::<T>(),
159             mem::align_of::<T>()
160         ) as *mut _ as *mut T;
161         // Write into uninitialized memory.
162         ptr::write(mem, object);
163         let result = &mut *mem;
164         // Record the destructor after doing the allocation as that may panic
165         // and would cause `object`'s destuctor to run twice if it was recorded before
166         self.destructors.borrow_mut().push(DropType {
167             drop_fn: drop_for_type::<T>,
168             obj: result as *mut T as *mut u8,
169         });
170         result
171     }
172
173     #[inline]
174     unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
175         let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
176         if vec.is_empty() {
177             return &mut [];
178         }
179         let len = vec.len();
180
181         let start_ptr = self.arena.alloc_raw(
182             len.checked_mul(mem::size_of::<T>()).unwrap(),
183             mem::align_of::<T>()
184         ) as *mut _ as *mut T;
185
186         let mut destructors = self.destructors.borrow_mut();
187         // Reserve space for the destructors so we can't panic while adding them
188         destructors.reserve(len);
189
190         // Move the content to the arena by copying it and then forgetting
191         // the content of the SmallVec
192         vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
193         mem::forget(vec.drain());
194
195         // Record the destructors after doing the allocation as that may panic
196         // and would cause `object`'s destuctor to run twice if it was recorded before
197         for i in 0..len {
198             destructors.push(DropType {
199                 drop_fn: drop_for_type::<T>,
200                 obj: start_ptr.offset(i as isize) as *mut u8,
201             });
202         }
203
204         slice::from_raw_parts_mut(start_ptr, len)
205     }
206 }