@@ -41,6 +41,15 @@ impl Pointer {
41
41
pub fn offset ( self , i : isize ) -> Self {
42
42
Pointer { offset : ( self . offset as isize + i) as usize , ..self }
43
43
}
44
+ pub fn points_to_zst ( & self ) -> bool {
45
+ self . alloc_id . 0 == 0
46
+ }
47
+ fn zst_ptr ( ) -> Self {
48
+ Pointer {
49
+ alloc_id : ZST_ALLOC_ID ,
50
+ offset : 0 ,
51
+ }
52
+ }
44
53
}
45
54
46
55
#[ derive( Debug , Copy , Clone , Hash , Eq , PartialEq ) ]
@@ -66,15 +75,29 @@ pub struct Memory<'a, 'tcx> {
66
75
pub layout : & ' a TargetDataLayout ,
67
76
}
68
77
78
+ const ZST_ALLOC_ID : AllocId = AllocId ( 0 ) ;
79
+
69
80
impl < ' a , ' tcx > Memory < ' a , ' tcx > {
70
81
pub fn new ( layout : & ' a TargetDataLayout ) -> Self {
71
- Memory {
82
+ let mut mem = Memory {
72
83
alloc_map : HashMap :: new ( ) ,
73
84
functions : HashMap :: new ( ) ,
74
85
function_alloc_cache : HashMap :: new ( ) ,
75
- next_id : AllocId ( 0 ) ,
86
+ next_id : AllocId ( 1 ) ,
76
87
layout : layout,
77
- }
88
+ } ;
89
+ // alloc id 0 is reserved for ZSTs, this is an optimization to prevent ZST
90
+ // (e.g. function items, (), [], ...) from requiring memory
91
+ let alloc = Allocation {
92
+ bytes : Vec :: new ( ) ,
93
+ relocations : BTreeMap :: new ( ) ,
94
+ undef_mask : UndefMask :: new ( 0 ) ,
95
+ } ;
96
+ mem. alloc_map . insert ( ZST_ALLOC_ID , alloc) ;
97
+ // check that additional zst allocs work
98
+ debug_assert ! ( mem. allocate( 0 ) . points_to_zst( ) ) ;
99
+ debug_assert ! ( mem. get( ZST_ALLOC_ID ) . is_ok( ) ) ;
100
+ mem
78
101
}
79
102
80
103
pub fn allocations < ' b > ( & ' b self ) -> :: std:: collections:: hash_map:: Iter < ' b , AllocId , Allocation > {
@@ -105,6 +128,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
105
128
}
106
129
107
130
pub fn allocate ( & mut self , size : usize ) -> Pointer {
131
+ if size == 0 {
132
+ return Pointer :: zst_ptr ( ) ;
133
+ }
108
134
let alloc = Allocation {
109
135
bytes : vec ! [ 0 ; size] ,
110
136
relocations : BTreeMap :: new ( ) ,
@@ -121,11 +147,14 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
121
147
122
148
// TODO(solson): Track which allocations were returned from __rust_allocate and report an error
123
149
// when reallocating/deallocating any others.
124
- pub fn reallocate ( & mut self , ptr : Pointer , new_size : usize ) -> EvalResult < ' tcx , ( ) > {
150
+ pub fn reallocate ( & mut self , ptr : Pointer , new_size : usize ) -> EvalResult < ' tcx , Pointer > {
125
151
if ptr. offset != 0 {
126
152
// TODO(solson): Report error about non-__rust_allocate'd pointer.
127
153
return Err ( EvalError :: Unimplemented ( format ! ( "bad pointer offset: {}" , ptr. offset) ) ) ;
128
154
}
155
+ if ptr. points_to_zst ( ) {
156
+ return Ok ( self . allocate ( new_size) ) ;
157
+ }
129
158
130
159
let size = self . get_mut ( ptr. alloc_id ) ?. bytes . len ( ) ;
131
160
@@ -141,21 +170,26 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
141
170
alloc. undef_mask . truncate ( new_size) ;
142
171
}
143
172
144
- Ok ( ( ) )
173
+ Ok ( ptr )
145
174
}
146
175
147
176
// TODO(solson): See comment on `reallocate`.
148
177
pub fn deallocate ( & mut self , ptr : Pointer ) -> EvalResult < ' tcx , ( ) > {
178
+ if ptr. points_to_zst ( ) {
179
+ return Ok ( ( ) ) ;
180
+ }
149
181
if ptr. offset != 0 {
150
182
// TODO(solson): Report error about non-__rust_allocate'd pointer.
151
183
return Err ( EvalError :: Unimplemented ( format ! ( "bad pointer offset: {}" , ptr. offset) ) ) ;
152
184
}
153
185
154
186
if self . alloc_map . remove ( & ptr. alloc_id ) . is_none ( ) {
187
+ debug ! ( "deallocated a pointer twice: {}" , ptr. alloc_id) ;
155
188
// TODO(solson): Report error about erroneous free. This is blocked on properly tracking
156
189
// already-dropped state since this if-statement is entered even in safe code without
157
190
// it.
158
191
}
192
+ debug ! ( "deallocated : {}" , ptr. alloc_id) ;
159
193
160
194
Ok ( ( ) )
161
195
}
0 commit comments