Skip to main content

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    pub fn take(&'_ mut self) -> Vec<T> {
172        // Safety: No GC can run during this call.
173        std::mem::take(unsafe { self.as_mut() })
174    }
175}
176
177impl<'a, T: 'a + RootKind> Deref for RootedGuard<'a, T> {
178    type Target = T;
179
180    /// This is unsound and will be removed eventually.
181    /// Use [`RootedGuard::as_ref`] instead.
182    fn deref(&self) -> &T {
183        unsafe { &(*self.root).data }
184    }
185}
186
187impl<'a, T: 'a + RootKind> Drop for RootedGuard<'a, T> {
188    fn drop(&mut self) {
189        // SAFETY: The `drop_in_place` invariants are upheld:
190        // https://doc.rust-lang.org/std/ptr/fn.drop_in_place.html#safety
191        unsafe {
192            let ptr = self.as_ptr();
193            ptr::drop_in_place(ptr);
194            ptr.write_bytes(0, 1);
195        }
196
197        unsafe {
198            (*self.root).remove_from_root_stack();
199        }
200    }
201}
202
203impl<'a, const N: usize> From<&RootedGuard<'a, ValueArray<N>>> for JS::HandleValueArray {
204    fn from(array: &RootedGuard<'a, ValueArray<N>>) -> JS::HandleValueArray {
205        JS::HandleValueArray::from(unsafe { &*array.root })
206    }
207}
208
209pub struct Handle<'a, T: 'a> {
210    pub(crate) ptr: NonNull<T>,
211    pub(crate) _phantom: PhantomData<&'a T>,
212}
213
214impl<T> Clone for Handle<'_, T> {
215    fn clone(&self) -> Self {
216        *self
217    }
218}
219
220impl<T> Copy for Handle<'_, T> {}
221
222#[cfg_attr(
223    feature = "crown",
224    crown::unrooted_must_root_lint::allow_unrooted_interior
225)]
226pub struct MutableHandle<'a, T: 'a> {
227    pub(crate) ptr: NonNull<T>,
228    anchor: PhantomData<&'a mut T>,
229}
230
231pub type HandleFunction<'a> = Handle<'a, *mut JSFunction>;
232pub type HandleId<'a> = Handle<'a, jsid>;
233pub type HandleObject<'a> = Handle<'a, *mut JSObject>;
234pub type HandleScript<'a> = Handle<'a, *mut JSScript>;
235pub type HandleString<'a> = Handle<'a, *mut JSString>;
236pub type HandleSymbol<'a> = Handle<'a, *mut Symbol>;
237pub type HandleValue<'a> = Handle<'a, Value>;
238
239pub type MutableHandleFunction<'a> = MutableHandle<'a, *mut JSFunction>;
240pub type MutableHandleId<'a> = MutableHandle<'a, jsid>;
241pub type MutableHandleObject<'a> = MutableHandle<'a, *mut JSObject>;
242pub type MutableHandleScript<'a> = MutableHandle<'a, *mut JSScript>;
243pub type MutableHandleString<'a> = MutableHandle<'a, *mut JSString>;
244pub type MutableHandleSymbol<'a> = MutableHandle<'a, *mut Symbol>;
245pub type MutableHandleValue<'a> = MutableHandle<'a, Value>;
246
247impl<'a, T> Handle<'a, T> {
248    pub fn get(&self) -> T
249    where
250        T: Copy,
251    {
252        unsafe { *self.ptr.as_ptr() }
253    }
254
255    /// Obtains a reference to the value pointed to by this handle.
256    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
257    ///
258    /// ```compile_fail
259    /// use mozjs::context::*;
260    /// use mozjs::jsapi::JSObject;
261    /// use mozjs::rooted;
262    ///
263    ///
264    /// fn gc(cx: &mut JSContext) {}
265    ///
266    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
267    ///     rooted!(&in(cx) let mut root = obj);
268    ///     let handle = root.handle();
269    ///     let r = handle.as_ref(cx);
270    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
271    ///     drop(r); // otherwise rust automatically drops r before gc call
272    /// }
273    /// ```
274    pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
275    where
276        'a: 's,
277    {
278        unsafe { self.ptr.as_ref() }
279    }
280
281    pub unsafe fn from_marked_location(ptr: *const T) -> Self {
282        Handle {
283            ptr: NonNull::new(ptr as *mut T).unwrap(),
284            _phantom: PhantomData,
285        }
286    }
287
288    pub unsafe fn from_raw(handle: RawHandle<T>) -> Self {
289        Handle::from_marked_location(handle.ptr)
290    }
291}
292
293impl<'a, T> IntoRawHandle for Handle<'a, T> {
294    type Target = T;
295    fn into_handle(self) -> RawHandle<T> {
296        unsafe { RawHandle::from_marked_location(self.ptr.as_ptr()) }
297    }
298}
299
300impl<'a, T> IntoRawHandle for MutableHandle<'a, T> {
301    type Target = T;
302    fn into_handle(self) -> RawHandle<T> {
303        unsafe { RawHandle::from_marked_location(self.ptr.as_ptr()) }
304    }
305}
306
307impl<'a, T> IntoRawMutableHandle for MutableHandle<'a, T> {
308    fn into_handle_mut(self) -> RawMutableHandle<T> {
309        unsafe { RawMutableHandle::from_marked_location(self.ptr.as_ptr()) }
310    }
311}
312
313impl<'a, T> Deref for Handle<'a, T> {
314    type Target = T;
315
316    /// This is unsound and will be removed eventually.
317    /// Use [`Handle::as_ref`] instead.
318    fn deref(&self) -> &T {
319        unsafe { self.ptr.as_ref() }
320    }
321}
322
323impl<'a, T> MutableHandle<'a, T> {
324    pub unsafe fn from_marked_location(ptr: *mut T) -> Self {
325        Self {
326            ptr: NonNull::new(ptr).unwrap(),
327            anchor: PhantomData,
328        }
329    }
330
331    pub unsafe fn from_raw(handle: RawMutableHandle<T>) -> Self {
332        MutableHandle::from_marked_location(handle.ptr)
333    }
334
335    pub fn handle(&self) -> Handle<'a, T> {
336        // SAFETY: This mutable handle was already derived from a marked location.
337        unsafe { Handle::from_marked_location(self.ptr.as_ptr()) }
338    }
339
340    pub fn get(&self) -> T
341    where
342        T: Copy,
343    {
344        unsafe { *self.ptr.as_ptr() }
345    }
346
347    pub fn set(&mut self, v: T)
348    where
349        T: Copy,
350    {
351        unsafe { *self.ptr.as_mut() = v }
352    }
353
354    /// Obtains a reference to the value pointed to by this handle.
355    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
356    ///
357    /// ```compile_fail
358    /// use mozjs::context::*;
359    /// use mozjs::jsapi::JSObject;
360    /// use mozjs::rooted;
361    ///
362    /// fn gc(cx: &mut JSContext) {}
363    ///
364    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
365    ///     rooted!(&in(cx) let mut root = obj);
366    ///     let handle = root.handle_mut();
367    ///     let r = handle.as_ref(cx);
368    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
369    ///     drop(r); // otherwise rust automatically drops r before gc call
370    /// }
371    /// ```
372    pub fn as_ref<'s: 'r, 'cx: 'r, 'r>(&'s self, _no_gc: &'cx NoGC) -> &'r T
373    where
374        'a: 's,
375    {
376        unsafe { self.ptr.as_ref() }
377    }
378
379    /// Obtains a reference to the value pointed to by this handle.
380    /// While this reference is alive, no GC can occur, because of the `_no_gc` argument:
381    ///
382    /// ```compile_fail
383    /// use mozjs::context::*;
384    /// use mozjs::jsapi::JSObject;
385    /// use mozjs::rooted;
386    ///
387    /// fn gc(cx: &mut JSContext) {}
388    ///
389    /// fn f(cx: &mut JSContext, obj: *mut JSObject) {
390    ///     rooted!(&in(cx) let mut root = obj);
391    ///     let mut handle = root.handle_mut();
392    ///     let r = handle.as_mut_ref(cx);
393    ///     gc(cx); // cannot call gc while r (thus cx borrow) is alive
394    ///     drop(r); // otherwise rust automatically drops r before gc call
395    /// }
396    /// ```
397    pub fn as_mut_ref<'s: 'r, 'cx: 'r, 'r>(&'s mut self, _no_gc: &'cx NoGC) -> &'r mut T
398    where
399        'a: 's,
400    {
401        unsafe { self.ptr.as_mut() }
402    }
403
404    /// Safety: GC must not run during the lifetime of the returned reference.
405    /// Use [`MutableHandle::as_mut_ref`] instead.
406    pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
407    where
408        'a: 'b,
409    {
410        self.ptr.as_mut()
411    }
412
413    /// Creates a copy of this object, with a shorter lifetime, that holds a
414    /// mutable borrow on the original object. When you write code that wants
415    /// to use a `MutableHandle` more than once, you will typically need to
416    /// call `reborrow` on all but the last usage. The same way that you might
417    /// naively clone a type to allow it to be passed to multiple functions.
418    ///
419    /// This is the same thing that happens with regular mutable references,
420    /// except there the compiler implicitly inserts the reborrow calls. Until
421    /// rust gains a feature to implicitly reborrow other types, we have to do
422    /// it by hand.
423    pub fn reborrow<'b>(&'b mut self) -> MutableHandle<'b, T>
424    where
425        'a: 'b,
426    {
427        MutableHandle {
428            ptr: self.ptr,
429            anchor: PhantomData,
430        }
431    }
432
433    pub(crate) fn raw(&mut self) -> RawMutableHandle<T> {
434        unsafe { RawMutableHandle::from_marked_location(self.ptr.as_ptr()) }
435    }
436}
437
438impl<'a, T> MutableHandle<'a, Option<T>> {
439    pub fn take(&mut self) -> Option<T> {
440        // Safety: No GC occurs during take call
441        unsafe { self.as_mut().take() }
442    }
443}
444
445impl<'a, T> Deref for MutableHandle<'a, T> {
446    type Target = T;
447
448    /// This is unsound and will be removed eventually.
449    /// Use [`MutableHandle::as_ref`] instead.
450    fn deref(&self) -> &T {
451        unsafe { self.ptr.as_ref() }
452    }
453}
454
455impl HandleValue<'static> {
456    pub fn null() -> Self {
457        unsafe { Self::from_raw(RawHandleValue::null()) }
458    }
459
460    pub fn undefined() -> Self {
461        unsafe { Self::from_raw(RawHandleValue::undefined()) }
462    }
463}
464
465impl<'a> HandleObject<'a> {
466    pub fn null() -> Self {
467        unsafe { Self::from_raw(RawHandleObject::null()) }
468    }
469}