extendr_api/
ownership.rs
1use once_cell::sync::Lazy;
12use std::collections::hash_map::{Entry, HashMap};
13use std::sync::Mutex;
14
15use extendr_ffi::{
16 R_NilValue, R_PreserveObject, R_ReleaseObject, R_xlen_t, Rf_allocVector, Rf_protect,
17 Rf_unprotect, LENGTH, SET_VECTOR_ELT, SEXP, SEXPTYPE, VECTOR_ELT,
18};
19
20mod send_sexp {
21 use extendr_ffi::SEXP;
27
28 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
30 pub struct SendSEXP(SEXP);
31
32 impl From<SEXP> for SendSEXP {
33 fn from(value: SEXP) -> Self {
34 Self(value)
35 }
36 }
37
38 unsafe impl Send for SendSEXP {}
41
42 impl SendSEXP {
43 pub unsafe fn inner(&self) -> SEXP {
45 self.0
46 }
47 }
48}
49
50use self::send_sexp::SendSEXP;
51
52static OWNERSHIP: Lazy<Mutex<Ownership>> = Lazy::new(|| Mutex::new(Ownership::new()));
53
54pub(crate) unsafe fn protect(sexp: SEXP) {
55 let mut own = OWNERSHIP.lock().expect("protect failed");
56 own.protect(sexp);
57}
58
59pub(crate) unsafe fn unprotect(sexp: SEXP) {
60 let mut own = OWNERSHIP.lock().expect("unprotect failed");
61 own.unprotect(sexp);
62}
63
64pub const INITIAL_PRESERVATION_SIZE: usize = 100000;
65pub const EXTRA_PRESERVATION_SIZE: usize = 100000;
66
67#[derive(Debug)]
71struct Object {
72 refcount: usize,
73 index: usize,
74}
75
76#[derive(Debug)]
78struct Ownership {
79 preservation: SendSEXP,
81
82 cur_index: usize,
84
85 max_index: usize,
87
88 objects: HashMap<SendSEXP, Object>,
90}
91
92impl Ownership {
93 fn new() -> Self {
94 unsafe {
95 let preservation =
96 Rf_allocVector(SEXPTYPE::VECSXP, INITIAL_PRESERVATION_SIZE as R_xlen_t);
97 R_PreserveObject(preservation);
98 Ownership {
99 preservation: preservation.into(),
100 cur_index: 0,
101 max_index: INITIAL_PRESERVATION_SIZE,
102 objects: HashMap::with_capacity(INITIAL_PRESERVATION_SIZE),
103 }
104 }
105 }
106
107 unsafe fn garbage_collect(&mut self) {
109 let new_size = self.cur_index * 2 + EXTRA_PRESERVATION_SIZE;
110 let new_sexp = Rf_allocVector(SEXPTYPE::VECSXP, new_size as R_xlen_t);
111 R_PreserveObject(new_sexp);
112 let old_sexp = self.preservation.inner();
113
114 let mut new_objects = HashMap::with_capacity(new_size);
115
116 let mut j = 0;
118 for (addr, object) in self.objects.iter() {
119 if object.refcount != 0 {
120 SET_VECTOR_ELT(new_sexp, j as R_xlen_t, addr.inner());
121 new_objects.insert(
122 addr.clone(),
123 Object {
124 refcount: object.refcount,
125 index: j,
126 },
127 );
128 j += 1;
129 }
130 }
131
132 R_ReleaseObject(old_sexp);
133 self.preservation = (new_sexp).into();
134 self.cur_index = j;
135 self.max_index = new_size;
136 self.objects = new_objects;
137 }
138
139 unsafe fn protect(&mut self, sexp: SEXP) {
140 Rf_protect(sexp);
149
150 if self.cur_index == self.max_index {
151 self.garbage_collect();
152 }
153
154 let send_sexp = sexp.into();
155 let Ownership {
156 ref mut preservation,
157 ref mut cur_index,
158 ref mut max_index,
159 ref mut objects,
160 } = *self;
161
162 let mut entry = objects.entry(send_sexp);
163 let preservation_sexp = preservation.inner();
164 match entry {
165 Entry::Occupied(ref mut occupied) => {
166 if occupied.get().refcount == 0 {
167 SET_VECTOR_ELT(preservation_sexp, occupied.get().index as R_xlen_t, sexp);
169 }
170 occupied.get_mut().refcount += 1;
171 }
172 Entry::Vacant(vacant) => {
173 let index = *cur_index;
174 SET_VECTOR_ELT(preservation_sexp, index as R_xlen_t, sexp);
175 *cur_index += 1;
176 assert!(index != *max_index);
177 let refcount = 1;
178 vacant.insert(Object { refcount, index });
179 }
180 }
181
182 Rf_unprotect(1);
183 }
184
185 pub unsafe fn unprotect(&mut self, sexp: SEXP) {
186 let send_sexp = sexp.into();
187 let Ownership {
188 preservation,
189 cur_index: _,
190 max_index: _,
191 ref mut objects,
192 } = self;
193
194 let mut entry = objects.entry(send_sexp);
195 match entry {
196 Entry::Occupied(ref mut occupied) => {
197 let object = occupied.get_mut();
198 if object.refcount == 0 {
199 panic!("Attempt to unprotect an already unprotected object.")
200 } else {
201 object.refcount -= 1;
202 if object.refcount == 0 {
203 let preservation_sexp = preservation.inner();
207 SET_VECTOR_ELT(preservation_sexp, object.index as R_xlen_t, R_NilValue);
208 }
209 }
210 }
211 Entry::Vacant(_) => {
212 panic!("Attempt to unprotect a never protected object.")
213 }
214 }
215 }
216
217 #[allow(dead_code)]
218 unsafe fn ref_count(&mut self, sexp: SEXP) -> usize {
219 let Ownership {
220 preservation: _,
221 cur_index: _,
222 max_index: _,
223 ref mut objects,
224 } = *self;
225
226 let mut entry = objects.entry(sexp.into());
227 match entry {
228 Entry::Occupied(ref mut occupied) => occupied.get().refcount,
229 Entry::Vacant(_) => 0,
230 }
231 }
232
233 #[allow(dead_code)]
235 unsafe fn check_objects(&mut self) {
236 let preservation_sexp = self.preservation.inner();
237 assert_eq!(self.max_index, LENGTH(preservation_sexp) as usize);
238
239 for (addr, object) in self.objects.iter() {
242 assert!(object.index < self.max_index);
243 let elt = VECTOR_ELT(preservation_sexp, object.index as R_xlen_t);
244 if object.refcount != 0 {
249 assert_eq!(elt, addr.inner());
251 } else {
252 assert_eq!(elt, R_NilValue);
254 }
255 }
256
257 for i in 0..self.max_index {
259 let elt = VECTOR_ELT(preservation_sexp, i as R_xlen_t);
260 if elt == R_NilValue {
261 assert_eq!(self.ref_count(elt), 0);
262 } else {
263 assert!(self.ref_count(elt) != 0);
264 }
265 }
266 }
268}
269
270#[cfg(test)]
271mod test {
272 use super::*;
273 use crate as extendr_api;
274 use crate::*;
275 use extendr_ffi::{Rf_ScalarInteger, Rf_protect};
276
277 #[test]
278 fn basic_test() {
279 test! {
280 single_threaded(|| unsafe {
281 {
282 let mut own = OWNERSHIP.lock().expect("lock failed");
283 own.check_objects();
284 }
285
286 let sexp1 = Rf_protect(Rf_ScalarInteger(1));
287 let sexp2 = Rf_protect(Rf_ScalarInteger(2));
288 protect(sexp1);
289 {
290 let mut own = OWNERSHIP.lock().expect("lock failed");
291 own.check_objects();
292 assert_eq!(own.ref_count(sexp1), 1);
293 assert_eq!(own.ref_count(sexp2), 0);
294 }
295
296 protect(sexp1);
297 {
298 let mut own = OWNERSHIP.lock().expect("lock failed");
299 own.check_objects();
300 assert_eq!(own.ref_count(sexp1), 2);
301 assert_eq!(own.ref_count(sexp2), 0);
302 }
303
304 unprotect(sexp1);
305 {
306 let mut own = OWNERSHIP.lock().expect("lock failed");
307 own.check_objects();
308 assert_eq!(own.ref_count(sexp1), 1);
309 assert_eq!(own.ref_count(sexp2), 0);
310 }
311
312 unprotect(sexp1);
313 {
314 let mut own = OWNERSHIP.lock().expect("lock failed");
315 own.check_objects();
316 assert_eq!(own.ref_count(sexp1), 0);
317 assert_eq!(own.ref_count(sexp2), 0);
318 }
319
320 protect(sexp2);
321 {
322 let mut own = OWNERSHIP.lock().expect("lock failed");
323 own.check_objects();
324 assert_eq!(own.ref_count(sexp1), 0);
325 assert_eq!(own.ref_count(sexp2), 1);
326 }
327
328 protect(sexp1);
329 {
330 let mut own = OWNERSHIP.lock().expect("lock failed");
331 own.check_objects();
332 assert_eq!(own.ref_count(sexp1), 1);
333 assert_eq!(own.ref_count(sexp2), 1);
334 }
335 Rf_unprotect(2);
336 });
337 }
338 }
339
340 #[test]
341 fn collection_test() {
342 test! {
343 single_threaded(|| unsafe {
344 {
345 let mut own = OWNERSHIP.lock().expect("protect failed");
346 own.check_objects();
347 }
348
349 let test_size = INITIAL_PRESERVATION_SIZE + EXTRA_PRESERVATION_SIZE * 5;
351
352 let sexp_pres = Rf_allocVector(SEXPTYPE::VECSXP, test_size as R_xlen_t);
354 Rf_protect(sexp_pres);
355
356 let sexps = (0..test_size).map(|i| {
357 let sexp = Rf_ScalarInteger(1);
358 SET_VECTOR_ELT(sexp_pres, i as R_xlen_t, sexp);
359 sexp
360 }).collect::<Vec<_>>();
361
362 for (i, sexp) in sexps.iter().enumerate() {
363 protect(*sexp);
364 if i % 2 == 0 {
365 unprotect(*sexp);
366 }
367 }
368
369 {
370 let mut own = OWNERSHIP.lock().expect("protect failed");
371 own.check_objects();
372 own.garbage_collect();
373 own.check_objects();
374 }
375
376 Rf_unprotect(1);
377 });
378 }
379 }
380}