mozjs/gc/
root.rs

1use std::marker::PhantomData;
2use std::mem::MaybeUninit;
3use std::ops::{Deref, IndexMut};
4use std::ptr;
5use std::ptr::NonNull;
6
7use crate::context::NoGC;
8use crate::jsapi::{jsid, JSContext, JSFunction, JSObject, JSScript, JSString, Symbol, Value, JS};
9use mozjs_sys::jsgc::{RootKind, Rooted};
10
11use crate::jsapi::Handle as RawHandle;
12use crate::jsapi::HandleObject as RawHandleObject;
13use crate::jsapi::HandleValue as RawHandleValue;
14use crate::jsapi::MutableHandle as RawMutableHandle;
15use mozjs_sys::jsgc::IntoHandle as IntoRawHandle;
16use mozjs_sys::jsgc::IntoMutableHandle as IntoRawMutableHandle;
17use mozjs_sys::jsgc::ValueArray;
18
19/// Rust API for keeping a Rooted value in the context's root stack.
20/// Example usage: `rooted!(in(cx) let x = UndefinedValue());`.
21/// `RootedGuard::new` also works, but the macro is preferred.
22#[cfg_attr(
23    feature = "crown",
24    crown::unrooted_must_root_lint::allow_unrooted_interior
25)]
26pub struct RootedGuard<'a, T: 'a + RootKind> {
27    root: *mut Rooted<T>,
28    anchor: PhantomData<&'a mut Rooted<T>>,
29}
30
31impl<'a, T: 'a + RootKind> RootedGuard<'a, T> {
32    pub fn new(cx: *mut JSContext, root: &'a mut MaybeUninit<Rooted<T>>, initial: T) -> Self {
33        let root: *mut Rooted<T> = root.write(Rooted::new_unrooted(initial));
34
35        unsafe {
36            Rooted::add_to_root_stack(root, cx);
37            RootedGuard {
38                root,
39                anchor: PhantomData,
40            }
41        }
42    }
43
44    pub fn handle(&'a self) -> Handle<'a, T> {
45        // SAFETY: A root is a marked location.
46        unsafe { Handle::from_marked_location(self.as_ptr()) }
47    }
48
49    pub fn handle_mut(&mut self) -> MutableHandle<T> {
50        unsafe { MutableHandle::from_marked_location(self.as_ptr()) }
51    }
52
53    pub fn as_ptr(&self) -> *mut T {
54        // SAFETY: self.root points to an inbounds allocation
55        unsafe { (&raw mut (*self.root).data) }
56    }
57
58    /// Obtains a reference to the value pointed to by this handle.
59    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
60    ///
61    /// ```compile_fail
62    /// use mozjs::context::*;
63    /// use mozjs::jsapi::JSObject;
64    /// use mozjs::rooted;
65    ///
66    /// fn gc(cx: &mut JSContext) {}
67    ///
68    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
69    ///     rooted!(&in(cx) let mut root = obj);
70    ///     let r = root.as_ref(cx);
71    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
72    ///     drop(r); // otherwise rust automatically drops r before gc call
73    /// }
74    /// ```
75    pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
76    where
77        'a: 's,
78    {
79        unsafe { &*(self.as_ptr()) }
80    }
81
82    /// Obtains a reference to the value pointed to by this handle.
83    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
84    ///
85    /// ```compile_fail
86    /// use mozjs::context::*;
87    /// use mozjs::jsapi::JSObject;
88    /// use mozjs::rooted;
89    ///
90    /// fn gc(cx: &mut JSContext) {}
91    ///
92    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
93    ///     rooted!(&in(cx) let mut root = obj);
94    ///     let r = root.as_mut_ref(cx);
95    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
96    ///     drop(r); // otherwise rust automatically drops r before gc call
97    /// }
98    /// ```
99    pub fn as_mut_ref<'s: 'r, 'cx: 'r, 'r>(&'s mut self, _no_gc: &'cx NoGC) -> &'r mut T
100    where
101        'a: 's,
102    {
103        unsafe { &mut *(self.as_ptr()) }
104    }
105
106    /// Safety: GC must not run during the lifetime of the returned reference.
107    /// Prefer using [`RootedGuard::as_mut_ref`] instead.
108    pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
109    where
110        'a: 'b,
111    {
112        &mut *(self.as_ptr())
113    }
114
115    pub fn get(&self) -> T
116    where
117        T: Copy,
118    {
119        *self.deref()
120    }
121
122    pub fn set(&mut self, v: T) {
123        // SAFETY: GC does not run during this block
124        unsafe { *self.as_mut() = v };
125    }
126}
127
128impl<'a, T> RootedGuard<'a, Option<T>>
129where
130    Option<T>: RootKind,
131{
132    pub fn take(&mut self) -> Option<T> {
133        // Safety: No GC occurs during take call
134        unsafe { self.as_mut().take() }
135    }
136}
137
138impl<'a, T> RootedGuard<'a, Vec<T>>
139where
140    Vec<T>: RootKind,
141{
142    pub fn push(&mut self, value: T) {
143        // Safety: No GC occurs during this call
144        unsafe { self.as_mut().push(value) }
145    }
146
147    pub fn extend(&mut self, iterator: impl Iterator<Item = T>) {
148        // Safety: No GC occurs during this call
149        unsafe { self.as_mut().extend(iterator) }
150    }
151
152    pub fn set_index(&mut self, index: usize, value: T) {
153        // Safety: No GC occurs during this call
154        unsafe {
155            *self.as_mut().index_mut(index) = value;
156        }
157    }
158
159    pub fn handle_at(&'_ self, index: usize) -> Handle<'_, T> {
160        assert!(index < self.len());
161        // Safety: Values within this rooted vector are traced.
162        unsafe { Handle::from_marked_location(self.deref().as_ptr().add(index)) }
163    }
164
165    pub fn handle_mut_at(&'_ mut self, index: usize) -> MutableHandle<'_, T> {
166        assert!(index < self.len());
167        // Safety: Values within this rooted vector are traced.
168        unsafe { MutableHandle::from_marked_location(self.as_mut().as_mut_ptr().add(index)) }
169    }
170}
171
172impl<'a, T: 'a + RootKind> Deref for RootedGuard<'a, T> {
173    type Target = T;
174
175    /// This is unsound and will be removed eventually.
176    /// Use [`RootedGuard::as_ref`] instead.
177    fn deref(&self) -> &T {
178        unsafe { &(*self.root).data }
179    }
180}
181
182impl<'a, T: 'a + RootKind> Drop for RootedGuard<'a, T> {
183    fn drop(&mut self) {
184        // SAFETY: The `drop_in_place` invariants are upheld:
185        // https://doc.rust-lang.org/std/ptr/fn.drop_in_place.html#safety
186        unsafe {
187            let ptr = self.as_ptr();
188            ptr::drop_in_place(ptr);
189            ptr.write_bytes(0, 1);
190        }
191
192        unsafe {
193            (*self.root).remove_from_root_stack();
194        }
195    }
196}
197
198impl<'a, const N: usize> From<&RootedGuard<'a, ValueArray<N>>> for JS::HandleValueArray {
199    fn from(array: &RootedGuard<'a, ValueArray<N>>) -> JS::HandleValueArray {
200        JS::HandleValueArray::from(unsafe { &*array.root })
201    }
202}
203
204pub struct Handle<'a, T: 'a> {
205    pub(crate) ptr: NonNull<T>,
206    pub(crate) _phantom: PhantomData<&'a T>,
207}
208
209impl<T> Clone for Handle<'_, T> {
210    fn clone(&self) -> Self {
211        *self
212    }
213}
214
215impl<T> Copy for Handle<'_, T> {}
216
217#[cfg_attr(
218    feature = "crown",
219    crown::unrooted_must_root_lint::allow_unrooted_interior
220)]
221pub struct MutableHandle<'a, T: 'a> {
222    pub(crate) ptr: NonNull<T>,
223    anchor: PhantomData<&'a mut T>,
224}
225
226pub type HandleFunction<'a> = Handle<'a, *mut JSFunction>;
227pub type HandleId<'a> = Handle<'a, jsid>;
228pub type HandleObject<'a> = Handle<'a, *mut JSObject>;
229pub type HandleScript<'a> = Handle<'a, *mut JSScript>;
230pub type HandleString<'a> = Handle<'a, *mut JSString>;
231pub type HandleSymbol<'a> = Handle<'a, *mut Symbol>;
232pub type HandleValue<'a> = Handle<'a, Value>;
233
234pub type MutableHandleFunction<'a> = MutableHandle<'a, *mut JSFunction>;
235pub type MutableHandleId<'a> = MutableHandle<'a, jsid>;
236pub type MutableHandleObject<'a> = MutableHandle<'a, *mut JSObject>;
237pub type MutableHandleScript<'a> = MutableHandle<'a, *mut JSScript>;
238pub type MutableHandleString<'a> = MutableHandle<'a, *mut JSString>;
239pub type MutableHandleSymbol<'a> = MutableHandle<'a, *mut Symbol>;
240pub type MutableHandleValue<'a> = MutableHandle<'a, Value>;
241
242impl<'a, T> Handle<'a, T> {
243    pub fn get(&self) -> T
244    where
245        T: Copy,
246    {
247        unsafe { *self.ptr.as_ptr() }
248    }
249
250    /// Obtains a reference to the value pointed to by this handle.
251    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
252    ///
253    /// ```compile_fail
254    /// use mozjs::context::*;
255    /// use mozjs::jsapi::JSObject;
256    /// use mozjs::rooted;
257    ///
258    ///
259    /// fn gc(cx: &mut JSContext) {}
260    ///
261    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
262    ///     rooted!(&in(cx) let mut root = obj);
263    ///     let handle = root.handle();
264    ///     let r = handle.as_ref(cx);
265    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
266    ///     drop(r); // otherwise rust automatically drops r before gc call
267    /// }
268    /// ```
269    pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
270    where
271        'a: 's,
272    {
273        unsafe { self.ptr.as_ref() }
274    }
275
276    pub unsafe fn from_marked_location(ptr: *const T) -> Self {
277        Handle {
278            ptr: NonNull::new(ptr as *mut T).unwrap(),
279            _phantom: PhantomData,
280        }
281    }
282
283    pub unsafe fn from_raw(handle: RawHandle<T>) -> Self {
284        Handle::from_marked_location(handle.ptr)
285    }
286}
287
288impl<'a, T> IntoRawHandle for Handle<'a, T> {
289    type Target = T;
290    fn into_handle(self) -> RawHandle<T> {
291        unsafe { RawHandle::from_marked_location(self.ptr.as_ptr()) }
292    }
293}
294
295impl<'a, T> IntoRawHandle for MutableHandle<'a, T> {
296    type Target = T;
297    fn into_handle(self) -> RawHandle<T> {
298        unsafe { RawHandle::from_marked_location(self.ptr.as_ptr()) }
299    }
300}
301
302impl<'a, T> IntoRawMutableHandle for MutableHandle<'a, T> {
303    fn into_handle_mut(self) -> RawMutableHandle<T> {
304        unsafe { RawMutableHandle::from_marked_location(self.ptr.as_ptr()) }
305    }
306}
307
308impl<'a, T> Deref for Handle<'a, T> {
309    type Target = T;
310
311    /// This is unsound and will be removed eventually.
312    /// Use [`Handle::as_ref`] instead.
313    fn deref(&self) -> &T {
314        unsafe { self.ptr.as_ref() }
315    }
316}
317
318impl<'a, T> MutableHandle<'a, T> {
319    pub unsafe fn from_marked_location(ptr: *mut T) -> Self {
320        Self {
321            ptr: NonNull::new(ptr).unwrap(),
322            anchor: PhantomData,
323        }
324    }
325
326    pub unsafe fn from_raw(handle: RawMutableHandle<T>) -> Self {
327        MutableHandle::from_marked_location(handle.ptr)
328    }
329
330    pub fn handle(&self) -> Handle<'a, T> {
331        // SAFETY: This mutable handle was already derived from a marked location.
332        unsafe { Handle::from_marked_location(self.ptr.as_ptr()) }
333    }
334
335    pub fn get(&self) -> T
336    where
337        T: Copy,
338    {
339        unsafe { *self.ptr.as_ptr() }
340    }
341
342    pub fn set(&mut self, v: T)
343    where
344        T: Copy,
345    {
346        unsafe { *self.ptr.as_mut() = v }
347    }
348
349    /// Obtains a reference to the value pointed to by this handle.
350    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
351    ///
352    /// ```compile_fail
353    /// use mozjs::context::*;
354    /// use mozjs::jsapi::JSObject;
355    /// use mozjs::rooted;
356    ///
357    /// fn gc(cx: &mut JSContext) {}
358    ///
359    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
360    ///     rooted!(&in(cx) let mut root = obj);
361    ///     let handle = root.handle_mut();
362    ///     let r = handle.as_ref(cx);
363    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
364    ///     drop(r); // otherwise rust automatically drops r before gc call
365    /// }
366    /// ```
367    pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
368    where
369        'a: 's,
370    {
371        unsafe { self.ptr.as_ref() }
372    }
373
374    /// Obtains a reference to the value pointed to by this handle.
375    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
376    ///
377    /// ```compile_fail
378    /// use mozjs::context::*;
379    /// use mozjs::jsapi::JSObject;
380    /// use mozjs::rooted;
381    ///
382    /// fn gc(cx: &mut JSContext) {}
383    ///
384    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
385    ///     rooted!(&in(cx) let mut root = obj);
386    ///     let mut handle = root.handle_mut();
387    ///     let r = handle.as_mut_ref(cx);
388    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
389    ///     drop(r); // otherwise rust automatically drops r before gc call
390    /// }
391    /// ```
392    pub fn as_mut_ref<'s: 'r, 'cx: 'r, 'r>(&'s mut self, _no_gc: &'cx NoGC) -> &'r mut T
393    where
394        'a: 's,
395    {
396        unsafe { self.ptr.as_mut() }
397    }
398
399    /// Safety: GC must not run during the lifetime of the returned reference.
400    /// Use [`MutableHandle::as_mut_ref`] instead.
401    pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
402    where
403        'a: 'b,
404    {
405        self.ptr.as_mut()
406    }
407
408    /// Creates a copy of this object, with a shorter lifetime, that holds a
409    /// mutable borrow on the original object. When you write code that wants
410    /// to use a `MutableHandle` more than once, you will typically need to
411    /// call `reborrow` on all but the last usage. The same way that you might
412    /// naively clone a type to allow it to be passed to multiple functions.
413    ///
414    /// This is the same thing that happens with regular mutable references,
415    /// except there the compiler implicitly inserts the reborrow calls. Until
416    /// rust gains a feature to implicitly reborrow other types, we have to do
417    /// it by hand.
418    pub fn reborrow<'b>(&'b mut self) -> MutableHandle<'b, T>
419    where
420        'a: 'b,
421    {
422        MutableHandle {
423            ptr: self.ptr,
424            anchor: PhantomData,
425        }
426    }
427
428    pub(crate) fn raw(&mut self) -> RawMutableHandle<T> {
429        unsafe { RawMutableHandle::from_marked_location(self.ptr.as_ptr()) }
430    }
431}
432
433impl<'a, T> MutableHandle<'a, Option<T>> {
434    pub fn take(&mut self) -> Option<T> {
435        // Safety: No GC occurs during take call
436        unsafe { self.as_mut().take() }
437    }
438}
439
440impl<'a, T> Deref for MutableHandle<'a, T> {
441    type Target = T;
442
443    /// This is unsound and will be removed eventually.
444    /// Use [`MutableHandle::as_ref`] instead.
445    fn deref(&self) -> &T {
446        unsafe { self.ptr.as_ref() }
447    }
448}
449
450impl HandleValue<'static> {
451    pub fn null() -> Self {
452        unsafe { Self::from_raw(RawHandleValue::null()) }
453    }
454
455    pub fn undefined() -> Self {
456        unsafe { Self::from_raw(RawHandleValue::undefined()) }
457    }
458}
459
460impl<'a> HandleObject<'a> {
461    pub fn null() -> Self {
462        unsafe { Self::from_raw(RawHandleObject::null()) }
463    }
464}