/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 | | } |