Coverage Report

Created: 2025-06-16 06:50

/rust/git/checkouts/mozjs-fa11ffc7d4f1cc2d/d90edd1/mozjs-sys/src/jsgc.rs
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
use crate::jsapi::JS;
6
use crate::jsapi::{jsid, JSFunction, JSObject, JSScript, JSString, JSTracer};
7
8
use crate::jsid::VoidId;
9
use std::cell::UnsafeCell;
10
use std::ffi::c_void;
11
use std::mem;
12
use std::ptr;
13
14
/// A trait for JS types that can be registered as roots.
15
pub trait RootKind {
16
    #[allow(non_snake_case)]
17
    /// Returns the rooting kind for `Self`.
18
    fn rootKind() -> JS::RootKind;
19
}
20
21
impl RootKind for *mut JSObject {
22
    #[inline(always)]
23
13.1k
    fn rootKind() -> JS::RootKind {
24
13.1k
        JS::RootKind::Object
25
13.1k
    }
26
}
27
28
impl RootKind for *mut JSFunction {
29
    #[inline(always)]
30
0
    fn rootKind() -> JS::RootKind {
31
0
        JS::RootKind::Object
32
0
    }
33
}
34
35
impl RootKind for *mut JSString {
36
    #[inline(always)]
37
0
    fn rootKind() -> JS::RootKind {
38
0
        JS::RootKind::String
39
0
    }
40
}
41
42
impl RootKind for *mut JS::Symbol {
43
    #[inline(always)]
44
0
    fn rootKind() -> JS::RootKind {
45
0
        JS::RootKind::Symbol
46
0
    }
47
}
48
49
impl RootKind for *mut JS::BigInt {
50
    #[inline(always)]
51
0
    fn rootKind() -> JS::RootKind {
52
0
        JS::RootKind::BigInt
53
0
    }
54
}
55
56
impl RootKind for *mut JSScript {
57
    #[inline(always)]
58
0
    fn rootKind() -> JS::RootKind {
59
0
        JS::RootKind::Script
60
0
    }
61
}
62
63
impl RootKind for jsid {
64
    #[inline(always)]
65
0
    fn rootKind() -> JS::RootKind {
66
0
        JS::RootKind::Id
67
0
    }
68
}
69
70
impl RootKind for JS::Value {
71
    #[inline(always)]
72
52.6k
    fn rootKind() -> JS::RootKind {
73
52.6k
        JS::RootKind::Value
74
52.6k
    }
75
}
76
77
impl RootKind for JS::PropertyDescriptor {
78
    #[inline(always)]
79
0
    fn rootKind() -> JS::RootKind {
80
0
        JS::RootKind::Traceable
81
0
    }
82
}
83
84
// Annoyingly, bindgen can't cope with SM's use of templates, so we have to roll our own.
85
#[repr(C)]
86
#[derive(Debug)]
87
pub struct Rooted<T> {
88
    pub stack: *mut *mut Rooted<*mut c_void>,
89
    pub prev: *mut Rooted<*mut c_void>,
90
    pub ptr: T,
91
}
92
93
/// A trait for types which can place appropriate GC barriers.
94
/// * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/Garbage_collection#Incremental_marking
95
/// * https://dxr.mozilla.org/mozilla-central/source/js/src/gc/Barrier.h
96
pub trait GCMethods {
97
    /// Create a default value
98
    unsafe fn initial() -> Self;
99
100
    /// Place a post-write barrier
101
    unsafe fn post_barrier(v: *mut Self, prev: Self, next: Self);
102
}
103
104
impl GCMethods for *mut JSObject {
105
13.1k
    unsafe fn initial() -> *mut JSObject {
106
13.1k
        ptr::null_mut()
107
13.1k
    }
108
0
    unsafe fn post_barrier(v: *mut *mut JSObject, prev: *mut JSObject, next: *mut JSObject) {
109
0
        JS::HeapObjectWriteBarriers(v, prev, next);
110
0
    }
111
}
112
113
impl GCMethods for *mut JSFunction {
114
0
    unsafe fn initial() -> *mut JSFunction {
115
0
        ptr::null_mut()
116
0
    }
117
0
    unsafe fn post_barrier(v: *mut *mut JSFunction, prev: *mut JSFunction, next: *mut JSFunction) {
118
0
        JS::HeapObjectWriteBarriers(
119
0
            mem::transmute(v),
120
0
            mem::transmute(prev),
121
0
            mem::transmute(next),
122
0
        );
123
0
    }
124
}
125
126
impl GCMethods for *mut JSString {
127
0
    unsafe fn initial() -> *mut JSString {
128
0
        ptr::null_mut()
129
0
    }
130
0
    unsafe fn post_barrier(v: *mut *mut JSString, prev: *mut JSString, next: *mut JSString) {
131
0
        JS::HeapStringWriteBarriers(v, prev, next);
132
0
    }
133
}
134
135
impl GCMethods for *mut JS::Symbol {
136
0
    unsafe fn initial() -> *mut JS::Symbol {
137
0
        ptr::null_mut()
138
0
    }
139
0
    unsafe fn post_barrier(_: *mut *mut JS::Symbol, _: *mut JS::Symbol, _: *mut JS::Symbol) {}
140
}
141
142
impl GCMethods for *mut JS::BigInt {
143
0
    unsafe fn initial() -> *mut JS::BigInt {
144
0
        ptr::null_mut()
145
0
    }
146
0
    unsafe fn post_barrier(v: *mut *mut JS::BigInt, prev: *mut JS::BigInt, next: *mut JS::BigInt) {
147
0
        JS::HeapBigIntWriteBarriers(v, prev, next);
148
0
    }
149
}
150
151
impl GCMethods for *mut JSScript {
152
0
    unsafe fn initial() -> *mut JSScript {
153
0
        ptr::null_mut()
154
0
    }
155
0
    unsafe fn post_barrier(v: *mut *mut JSScript, prev: *mut JSScript, next: *mut JSScript) {
156
0
        JS::HeapScriptWriteBarriers(v, prev, next);
157
0
    }
158
}
159
160
impl GCMethods for jsid {
161
0
    unsafe fn initial() -> jsid {
162
0
        VoidId()
163
0
    }
164
0
    unsafe fn post_barrier(_: *mut jsid, _: jsid, _: jsid) {}
165
}
166
167
impl GCMethods for JS::Value {
168
52.6k
    unsafe fn initial() -> JS::Value {
169
52.6k
        JS::Value::default()
170
52.6k
    }
171
0
    unsafe fn post_barrier(v: *mut JS::Value, prev: JS::Value, next: JS::Value) {
172
0
        JS::HeapValueWriteBarriers(v, &prev, &next);
173
0
    }
174
}
175
176
impl GCMethods for JS::PropertyDescriptor {
177
0
    unsafe fn initial() -> JS::PropertyDescriptor {
178
0
        JS::PropertyDescriptor::default()
179
0
    }
180
0
    unsafe fn post_barrier(
181
0
        _: *mut JS::PropertyDescriptor,
182
0
        _: JS::PropertyDescriptor,
183
0
        _: JS::PropertyDescriptor,
184
0
    ) {
185
0
    }
186
}
187
188
/// A fixed-size array of values, for use inside Rooted<>.
189
///
190
/// https://searchfox.org/mozilla-central/source/js/public/ValueArray.h#31
191
pub struct ValueArray<const N: usize> {
192
    elements: [JS::Value; N],
193
}
194
195
impl<const N: usize> ValueArray<N> {
196
0
    pub fn new(elements: [JS::Value; N]) -> Self {
197
0
        Self { elements }
198
0
    }
199
200
0
    pub fn to_handle_value_array(&self) -> JS::HandleValueArray {
201
0
        JS::HandleValueArray {
202
0
            length_: N,
203
0
            elements_: self.elements.as_ptr(),
204
0
        }
205
0
    }
206
207
0
    pub unsafe fn get_ptr(&self) -> *const JS::Value {
208
0
        self.elements.as_ptr()
209
0
    }
210
211
0
    pub unsafe fn get_mut_ptr(&self) -> *mut JS::Value {
212
0
        self.elements.as_ptr() as *mut _
213
0
    }
214
}
215
216
impl<const N: usize> RootKind for ValueArray<N> {
217
0
    fn rootKind() -> JS::RootKind {
218
0
        JS::RootKind::Traceable
219
0
    }
220
}
221
222
impl<const N: usize> GCMethods for ValueArray<N> {
223
0
    unsafe fn initial() -> Self {
224
0
        Self {
225
0
            elements: [JS::Value::initial(); N],
226
0
        }
227
0
    }
228
0
    unsafe fn post_barrier(_: *mut Self, _: Self, _: Self) {}
229
}
230
231
/// RootedValueArray roots an internal fixed-size array of Values
232
pub type RootedValueArray<const N: usize> = Rooted<ValueArray<N>>;
233
234
/// Heap values encapsulate GC concerns of an on-heap reference to a JS
235
/// object. This means that every reference to a JS object on heap must
236
/// be realized through this structure.
237
///
238
/// # Safety
239
/// For garbage collection to work correctly in SpiderMonkey, modifying the
240
/// wrapped value triggers a GC barrier, pointing to the underlying object.
241
///
242
/// This means that after calling the `set()` function with a non-null or
243
/// non-undefined value, the `Heap` wrapper *must not* be moved, since doing
244
/// so will invalidate the local reference to wrapped value, still held by
245
/// SpiderMonkey.
246
///
247
/// For safe `Heap` construction with value see `Heap::boxed` function.
248
#[repr(C)]
249
#[derive(Debug)]
250
pub struct Heap<T: GCMethods + Copy> {
251
    pub ptr: UnsafeCell<T>,
252
}
253
254
impl<T: GCMethods + Copy> Heap<T> {
255
    /// This creates a `Box`-wrapped Heap value. Setting a value inside Heap
256
    /// object triggers a barrier, referring to the Heap object location,
257
    /// hence why it is not safe to construct a temporary Heap value, assign
258
    /// a non-null value and move it (e.g. typical object construction).
259
    ///
260
    /// Using boxed Heap value guarantees that the underlying Heap value will
261
    /// not be moved when constructed.
262
0
    pub fn boxed(v: T) -> Box<Heap<T>>
263
0
    where
264
0
        Heap<T>: Default,
265
0
    {
266
0
        let boxed = Box::new(Heap::default());
267
0
        boxed.set(v);
268
0
        boxed
269
0
    }
270
271
0
    pub fn set(&self, v: T) {
272
0
        unsafe {
273
0
            let ptr = self.ptr.get();
274
0
            let prev = *ptr;
275
0
            *ptr = v;
276
0
            T::post_barrier(ptr, prev, v);
277
0
        }
278
0
    }
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<*mut mozjs_sys::generated::root::JSObject>>::set
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<_>>::set
279
280
0
    pub fn get(&self) -> T {
281
0
        unsafe { *self.ptr.get() }
282
0
    }
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<*mut mozjs_sys::generated::root::JSObject>>::get
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<*mut mozjs_sys::generated::root::JS::BigInt>>::get
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<*mut mozjs_sys::generated::root::JS::Symbol>>::get
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<_>>::get
283
284
0
    pub fn get_unsafe(&self) -> *mut T {
285
0
        self.ptr.get()
286
0
    }
287
288
    /// Retrieves a Handle to the underlying value.
289
    ///
290
    /// # Safety
291
    ///
292
    /// This is only safe to do on a rooted object (which Heap is not, it needs
293
    /// to be additionally rooted), like RootedGuard, so use this only if you
294
    /// know what you're doing.
295
    ///
296
    /// # Notes
297
    ///
298
    /// Since Heap values need to be informed when a change to underlying
299
    /// value is made (e.g. via `get()`), this does not allow to create
300
    /// MutableHandle objects, which can bypass this and lead to crashes.
301
0
    pub unsafe fn handle(&self) -> JS::Handle<T> {
302
0
        JS::Handle::from_marked_location(self.ptr.get() as *const _)
303
0
    }
304
}
305
306
impl<T> Default for Heap<*mut T>
307
where
308
    *mut T: GCMethods + Copy,
309
{
310
0
    fn default() -> Heap<*mut T> {
311
0
        Heap {
312
0
            ptr: UnsafeCell::new(ptr::null_mut()),
313
0
        }
314
0
    }
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<*mut mozjs_sys::generated::root::JSObject> as core::default::Default>::default
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<*mut _> as core::default::Default>::default
315
}
316
317
impl Default for Heap<JS::Value> {
318
0
    fn default() -> Heap<JS::Value> {
319
0
        Heap {
320
0
            ptr: UnsafeCell::new(JS::Value::default()),
321
0
        }
322
0
    }
323
}
324
325
impl<T: GCMethods + Copy> Drop for Heap<T> {
326
0
    fn drop(&mut self) {
327
0
        unsafe {
328
0
            let ptr = self.ptr.get();
329
0
            T::post_barrier(ptr, *ptr, T::initial());
330
0
        }
331
0
    }
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<*mut mozjs_sys::generated::root::JSObject> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <mozjs_sys::jsgc::Heap<_> as core::ops::drop::Drop>::drop
332
}
333
334
impl<T: GCMethods + Copy + PartialEq> PartialEq for Heap<T> {
335
0
    fn eq(&self, other: &Self) -> bool {
336
0
        self.get() == other.get()
337
0
    }
338
}
339
340
/// Trait for things that can be converted to handles
341
/// For any type `T: IntoHandle` we have an implementation of `From<T>`
342
/// for `MutableHandle<T::Target>`. This is a way round the orphan
343
/// rule.
344
pub trait IntoHandle {
345
    /// The type of the handle
346
    type Target;
347
348
    /// Convert this object to a handle.
349
    fn into_handle(self) -> JS::Handle<Self::Target>;
350
}
351
352
pub trait IntoMutableHandle: IntoHandle {
353
    /// Convert this object to a mutable handle.
354
    fn into_handle_mut(self) -> JS::MutableHandle<Self::Target>;
355
}
356
357
impl<T: IntoHandle> From<T> for JS::Handle<T::Target> {
358
13.1k
    fn from(value: T) -> Self {
359
13.1k
        value.into_handle()
360
13.1k
    }
Unexecuted instantiation: <mozjs_sys::generated::root::JS::Handle<<mozjs::gc::root::Handle<mozjs_sys::generated::root::JS::Value> as mozjs_sys::jsgc::IntoHandle>::Target> as core::convert::From<mozjs::gc::root::Handle<mozjs_sys::generated::root::JS::Value>>>::from
<mozjs_sys::generated::root::JS::Handle<<mozjs::gc::root::Handle<*mut mozjs_sys::generated::root::JSObject> as mozjs_sys::jsgc::IntoHandle>::Target> as core::convert::From<mozjs::gc::root::Handle<*mut mozjs_sys::generated::root::JSObject>>>::from
Line
Count
Source
358
13.1k
    fn from(value: T) -> Self {
359
13.1k
        value.into_handle()
360
13.1k
    }
Unexecuted instantiation: <mozjs_sys::generated::root::JS::Handle<<_ as mozjs_sys::jsgc::IntoHandle>::Target> as core::convert::From<_>>::from
361
}
362
363
impl<T: IntoMutableHandle> From<T> for JS::MutableHandle<T::Target> {
364
39.4k
    fn from(value: T) -> Self {
365
39.4k
        value.into_handle_mut()
366
39.4k
    }
<mozjs_sys::generated::root::JS::MutableHandle<<mozjs::gc::root::MutableHandle<mozjs_sys::generated::root::JS::Value> as mozjs_sys::jsgc::IntoHandle>::Target> as core::convert::From<mozjs::gc::root::MutableHandle<mozjs_sys::generated::root::JS::Value>>>::from
Line
Count
Source
364
39.4k
    fn from(value: T) -> Self {
365
39.4k
        value.into_handle_mut()
366
39.4k
    }
Unexecuted instantiation: <mozjs_sys::generated::root::JS::MutableHandle<<_ as mozjs_sys::jsgc::IntoHandle>::Target> as core::convert::From<_>>::from
367
}
368
369
/// Methods for a CustomAutoRooter
370
#[repr(C)]
371
pub struct CustomAutoRooterVFTable {
372
    #[cfg(windows)]
373
    pub padding: [usize; 1],
374
    #[cfg(not(windows))]
375
    pub padding: [usize; 2],
376
    pub trace: unsafe extern "C" fn(this: *mut c_void, trc: *mut JSTracer),
377
}
378
379
impl CustomAutoRooterVFTable {
380
    #[cfg(windows)]
381
    pub const PADDING: [usize; 1] = [0];
382
    #[cfg(not(windows))]
383
    pub const PADDING: [usize; 2] = [0, 0];
384
}