mozjs/gc/
root.rs

1use std::marker::PhantomData;
2use std::mem::MaybeUninit;
3use std::ops::Deref;
4use std::ptr;
5
6use crate::jsapi::{jsid, JSContext, JSFunction, JSObject, JSScript, JSString, Symbol, Value, JS};
7use mozjs_sys::jsgc::{RootKind, Rooted};
8
9use crate::jsapi::Handle as RawHandle;
10use crate::jsapi::HandleValue as RawHandleValue;
11use crate::jsapi::MutableHandle as RawMutableHandle;
12use mozjs_sys::jsgc::IntoHandle as IntoRawHandle;
13use mozjs_sys::jsgc::IntoMutableHandle as IntoRawMutableHandle;
14use mozjs_sys::jsgc::ValueArray;
15
16/// Rust API for keeping a Rooted value in the context's root stack.
17/// Example usage: `rooted!(in(cx) let x = UndefinedValue());`.
18/// `RootedGuard::new` also works, but the macro is preferred.
19#[cfg_attr(
20    feature = "crown",
21    crown::unrooted_must_root_lint::allow_unrooted_interior
22)]
23pub struct RootedGuard<'a, T: 'a + RootKind> {
24    root: *mut Rooted<T>,
25    anchor: PhantomData<&'a mut Rooted<T>>,
26}
27
28impl<'a, T: 'a + RootKind> RootedGuard<'a, T> {
29    pub fn new(cx: *mut JSContext, root: &'a mut MaybeUninit<Rooted<T>>, initial: T) -> Self {
30        let root: *mut Rooted<T> = root.write(Rooted::new_unrooted(initial));
31
32        unsafe {
33            Rooted::add_to_root_stack(root, cx);
34            RootedGuard {
35                root,
36                anchor: PhantomData,
37            }
38        }
39    }
40
41    pub fn handle(&'a self) -> Handle<'a, T> {
42        Handle::new(&self)
43    }
44
45    pub fn handle_mut(&mut self) -> MutableHandle<T> {
46        unsafe { MutableHandle::from_marked_location(self.as_ptr()) }
47    }
48
49    pub fn as_ptr(&self) -> *mut T {
50        // SAFETY: self.root points to an inbounds allocation
51        unsafe { (&raw mut (*self.root).data) }
52    }
53
54    /// Safety: GC must not run during the lifetime of the returned reference.
55    pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
56    where
57        'a: 'b,
58    {
59        &mut *(self.as_ptr())
60    }
61
62    pub fn get(&self) -> T
63    where
64        T: Copy,
65    {
66        *self.deref()
67    }
68
69    pub fn set(&mut self, v: T) {
70        // SAFETY: GC does not run during this block
71        unsafe { *self.as_mut() = v };
72    }
73}
74
75impl<'a, T> RootedGuard<'a, Option<T>>
76where
77    Option<T>: RootKind,
78{
79    pub fn take(&mut self) -> Option<T> {
80        // Safety: No GC occurs during take call
81        unsafe { self.as_mut().take() }
82    }
83}
84
85impl<'a, T: 'a + RootKind> Deref for RootedGuard<'a, T> {
86    type Target = T;
87    fn deref(&self) -> &T {
88        unsafe { &(*self.root).data }
89    }
90}
91
92impl<'a, T: 'a + RootKind> Drop for RootedGuard<'a, T> {
93    fn drop(&mut self) {
94        // SAFETY: The `drop_in_place` invariants are upheld:
95        // https://doc.rust-lang.org/std/ptr/fn.drop_in_place.html#safety
96        unsafe {
97            let ptr = self.as_ptr();
98            ptr::drop_in_place(ptr);
99            ptr.write_bytes(0, 1);
100        }
101
102        unsafe {
103            (*self.root).remove_from_root_stack();
104        }
105    }
106}
107
108impl<'a, const N: usize> From<&RootedGuard<'a, ValueArray<N>>> for JS::HandleValueArray {
109    fn from(array: &RootedGuard<'a, ValueArray<N>>) -> JS::HandleValueArray {
110        JS::HandleValueArray::from(unsafe { &*array.root })
111    }
112}
113
114pub struct Handle<'a, T: 'a> {
115    pub(crate) ptr: &'a T,
116}
117
118impl<T> Clone for Handle<'_, T> {
119    fn clone(&self) -> Self {
120        *self
121    }
122}
123
124impl<T> Copy for Handle<'_, T> {}
125
126#[cfg_attr(
127    feature = "crown",
128    crown::unrooted_must_root_lint::allow_unrooted_interior
129)]
130pub struct MutableHandle<'a, T: 'a> {
131    pub(crate) ptr: *mut T,
132    anchor: PhantomData<&'a mut T>,
133}
134
135pub type HandleFunction<'a> = Handle<'a, *mut JSFunction>;
136pub type HandleId<'a> = Handle<'a, jsid>;
137pub type HandleObject<'a> = Handle<'a, *mut JSObject>;
138pub type HandleScript<'a> = Handle<'a, *mut JSScript>;
139pub type HandleString<'a> = Handle<'a, *mut JSString>;
140pub type HandleSymbol<'a> = Handle<'a, *mut Symbol>;
141pub type HandleValue<'a> = Handle<'a, Value>;
142
143pub type MutableHandleFunction<'a> = MutableHandle<'a, *mut JSFunction>;
144pub type MutableHandleId<'a> = MutableHandle<'a, jsid>;
145pub type MutableHandleObject<'a> = MutableHandle<'a, *mut JSObject>;
146pub type MutableHandleScript<'a> = MutableHandle<'a, *mut JSScript>;
147pub type MutableHandleString<'a> = MutableHandle<'a, *mut JSString>;
148pub type MutableHandleSymbol<'a> = MutableHandle<'a, *mut Symbol>;
149pub type MutableHandleValue<'a> = MutableHandle<'a, Value>;
150
151impl<'a, T> Handle<'a, T> {
152    pub fn get(&self) -> T
153    where
154        T: Copy,
155    {
156        *self.ptr
157    }
158
159    pub(crate) fn new(ptr: &'a T) -> Self {
160        Handle { ptr }
161    }
162
163    pub unsafe fn from_marked_location(ptr: *const T) -> Self {
164        Handle::new(&*ptr)
165    }
166
167    pub unsafe fn from_raw(handle: RawHandle<T>) -> Self {
168        Handle::from_marked_location(handle.ptr)
169    }
170}
171
172impl<'a, T> IntoRawHandle for Handle<'a, T> {
173    type Target = T;
174    fn into_handle(self) -> RawHandle<T> {
175        unsafe { RawHandle::from_marked_location(self.ptr) }
176    }
177}
178
179impl<'a, T> IntoRawHandle for MutableHandle<'a, T> {
180    type Target = T;
181    fn into_handle(self) -> RawHandle<T> {
182        unsafe { RawHandle::from_marked_location(self.ptr) }
183    }
184}
185
186impl<'a, T> IntoRawMutableHandle for MutableHandle<'a, T> {
187    fn into_handle_mut(self) -> RawMutableHandle<T> {
188        unsafe { RawMutableHandle::from_marked_location(self.ptr) }
189    }
190}
191
192impl<'a, T> Deref for Handle<'a, T> {
193    type Target = T;
194
195    fn deref(&self) -> &T {
196        self.ptr
197    }
198}
199
200impl<'a, T> MutableHandle<'a, T> {
201    pub unsafe fn from_marked_location(ptr: *mut T) -> Self {
202        MutableHandle::new(&mut *ptr)
203    }
204
205    pub unsafe fn from_raw(handle: RawMutableHandle<T>) -> Self {
206        MutableHandle::from_marked_location(handle.ptr)
207    }
208
209    pub fn handle(&self) -> Handle<T> {
210        unsafe { Handle::new(&*self.ptr) }
211    }
212
213    pub(crate) fn new(ptr: &'a mut T) -> Self {
214        Self {
215            ptr,
216            anchor: PhantomData,
217        }
218    }
219
220    pub fn get(&self) -> T
221    where
222        T: Copy,
223    {
224        unsafe { *self.ptr }
225    }
226
227    pub fn set(&mut self, v: T)
228    where
229        T: Copy,
230    {
231        unsafe { *self.ptr = v }
232    }
233
234    /// Safety: GC must not run during the lifetime of the returned reference.
235    pub unsafe fn as_mut<'b>(&'b mut self) -> &'b mut T
236    where
237        'a: 'b,
238    {
239        &mut *(self.ptr)
240    }
241
242    /// Creates a copy of this object, with a shorter lifetime, that holds a
243    /// mutable borrow on the original object. When you write code that wants
244    /// to use a `MutableHandle` more than once, you will typically need to
245    /// call `reborrow` on all but the last usage. The same way that you might
246    /// naively clone a type to allow it to be passed to multiple functions.
247    ///
248    /// This is the same thing that happens with regular mutable references,
249    /// except there the compiler implicitly inserts the reborrow calls. Until
250    /// rust gains a feature to implicitly reborrow other types, we have to do
251    /// it by hand.
252    pub fn reborrow<'b>(&'b mut self) -> MutableHandle<'b, T>
253    where
254        'a: 'b,
255    {
256        MutableHandle {
257            ptr: self.ptr,
258            anchor: PhantomData,
259        }
260    }
261
262    pub(crate) fn raw(&mut self) -> RawMutableHandle<T> {
263        unsafe { RawMutableHandle::from_marked_location(self.ptr) }
264    }
265}
266
267impl<'a, T> MutableHandle<'a, Option<T>> {
268    pub fn take(&mut self) -> Option<T> {
269        // Safety: No GC occurs during take call
270        unsafe { self.as_mut().take() }
271    }
272}
273
274impl<'a, T> Deref for MutableHandle<'a, T> {
275    type Target = T;
276
277    fn deref(&self) -> &T {
278        unsafe { &*self.ptr }
279    }
280}
281
282impl HandleValue<'static> {
283    pub fn null() -> Self {
284        unsafe { Self::from_raw(RawHandleValue::null()) }
285    }
286
287    pub fn undefined() -> Self {
288        unsafe { Self::from_raw(RawHandleValue::undefined()) }
289    }
290}
291
292const ConstNullValue: *mut JSObject = ptr::null_mut();
293
294impl<'a> HandleObject<'a> {
295    pub fn null() -> Self {
296        unsafe { HandleObject::from_marked_location(&ConstNullValue) }
297    }
298}