1
1
use arena:: { TypedArena , DroplessArena } ;
2
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 ;
3
8
4
9
#[ macro_export]
5
10
macro_rules! arena_types {
@@ -9,29 +14,55 @@ macro_rules! arena_types {
9
14
rustc:: hir:: def_id:: DefId ,
10
15
rustc:: ty:: subst:: SubstsRef <$tcx>
11
16
) >,
17
+ [ few] mir_keys: rustc:: util:: nodemap:: DefIdSet ,
12
18
[ decode] specialization_graph: rustc:: traits:: specialization_graph:: Graph ,
13
19
] , $tcx) ;
14
20
)
15
21
}
16
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
+
17
35
macro_rules! declare_arena {
18
36
( [ ] , [ $( $a: tt $name: ident: $ty: ty, ) * ] , $tcx: lifetime) => {
19
37
#[ derive( Default ) ]
20
38
pub struct Arena <$tcx> {
21
39
dropless: DroplessArena ,
22
- $( $name: TypedArena <$ty>, ) *
40
+ drop: DropArena ,
41
+ $( $name: arena_for_type!( $a[ $ty] ) , ) *
23
42
}
24
43
}
25
44
}
26
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
+
27
58
macro_rules! impl_arena_allocatable {
28
59
( [ ] , [ $( $a: tt $name: ident: $ty: ty, ) * ] , $tcx: lifetime) => {
29
60
$(
30
61
impl ArenaAllocatable for $ty { }
31
- impl <$tcx> ArenaField <$tcx> for $ty {
62
+ unsafe impl <$tcx> ArenaField <$tcx> for $ty {
32
63
#[ inline]
33
- fn arena<' a>( arena : & ' a Arena <$tcx>) -> & ' a TypedArena <Self > {
34
- & arena . $name
64
+ fn arena<' a>( _arena : & ' a Arena <$tcx>) -> Option < & ' a TypedArena <Self > > {
65
+ which_arena_for_type! ( $a [ & _arena . $name] )
35
66
}
36
67
}
37
68
) *
@@ -46,39 +77,130 @@ pub trait ArenaAllocatable {}
46
77
47
78
impl < T : Copy > ArenaAllocatable for T { }
48
79
49
- pub trait ArenaField < ' tcx > : Sized {
80
+ pub unsafe trait ArenaField < ' tcx > : Sized {
50
81
/// Returns a specific arena to allocate from.
51
- fn arena < ' a > ( arena : & ' a Arena < ' tcx > ) -> & ' a TypedArena < Self > ;
82
+ /// If None is returned, the DropArena will be used.
83
+ fn arena < ' a > ( arena : & ' a Arena < ' tcx > ) -> Option < & ' a TypedArena < Self > > ;
52
84
}
53
85
54
- impl < ' tcx , T > ArenaField < ' tcx > for T {
86
+ unsafe impl < ' tcx , T > ArenaField < ' tcx > for T {
55
87
#[ inline]
56
- default fn arena < ' a > ( _: & ' a Arena < ' tcx > ) -> & ' a TypedArena < Self > {
88
+ default fn arena < ' a > ( _: & ' a Arena < ' tcx > ) -> Option < & ' a TypedArena < Self > > {
57
89
panic ! ( )
58
90
}
59
91
}
60
92
61
93
impl < ' tcx > Arena < ' tcx > {
62
94
#[ inline]
63
95
pub fn alloc < T : ArenaAllocatable > ( & self , value : T ) -> & mut T {
64
- if mem:: needs_drop :: < T > ( ) {
65
- <T as ArenaField < ' tcx > >:: arena ( self ) . alloc ( value)
66
- } else {
67
- self . dropless . alloc ( value)
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) } ,
68
102
}
69
103
}
70
104
71
105
pub fn alloc_from_iter <
72
106
T : ArenaAllocatable ,
73
107
I : IntoIterator < Item = T >
74
108
> (
75
- & self ,
109
+ & ' a self ,
76
110
iter : I
77
- ) -> & mut [ T ] {
78
- if mem:: needs_drop :: < T > ( ) {
79
- <T as ArenaField < ' tcx > >:: arena ( self ) . alloc_from_iter ( iter)
80
- } else {
81
- self . dropless . alloc_from_iter ( iter)
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 safetly, 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 [ ] ;
82
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)
83
205
}
84
206
}
0 commit comments