1use crate::jsapi::{js, JS};
6use crate::jsapi::{jsid, JSFunction, JSObject, JSScript, JSString, JSTracer};
7use crate::jsid::VoidId;
8use std::cell::UnsafeCell;
9use std::collections::VecDeque;
10use std::ffi::{c_char, c_void};
11use std::marker::PhantomData;
12use std::mem;
13use std::ptr;
14
15pub trait RootKind {
17 type Vtable;
18 const VTABLE: Self::Vtable;
19 const KIND: JS::RootKind;
20}
21
22impl RootKind for *mut JSObject {
23 type Vtable = ();
24 const VTABLE: Self::Vtable = ();
25 const KIND: JS::RootKind = JS::RootKind::Object;
26}
27
28impl RootKind for *mut JSFunction {
29 type Vtable = ();
30 const VTABLE: Self::Vtable = ();
31 const KIND: JS::RootKind = JS::RootKind::Object;
32}
33
34impl RootKind for *mut JSString {
35 type Vtable = ();
36 const VTABLE: Self::Vtable = ();
37 const KIND: JS::RootKind = JS::RootKind::String;
38}
39
40impl RootKind for *mut JS::Symbol {
41 type Vtable = ();
42 const VTABLE: Self::Vtable = ();
43 const KIND: JS::RootKind = JS::RootKind::Symbol;
44}
45
46impl RootKind for *mut JS::BigInt {
47 type Vtable = ();
48 const VTABLE: Self::Vtable = ();
49 const KIND: JS::RootKind = JS::RootKind::BigInt;
50}
51
52impl RootKind for *mut JSScript {
53 type Vtable = ();
54 const VTABLE: Self::Vtable = ();
55 const KIND: JS::RootKind = JS::RootKind::Script;
56}
57
58impl RootKind for jsid {
59 type Vtable = ();
60 const VTABLE: Self::Vtable = ();
61 const KIND: JS::RootKind = JS::RootKind::Id;
62}
63
64impl RootKind for JS::Value {
65 type Vtable = ();
66 const VTABLE: Self::Vtable = ();
67 const KIND: JS::RootKind = JS::RootKind::Value;
68}
69
70impl<T: Rootable> RootKind for T {
71 type Vtable = *const RootedVFTable;
72 const VTABLE: Self::Vtable = &<Self as Rootable>::VTABLE;
73 const KIND: JS::RootKind = JS::RootKind::Traceable;
74}
75
76#[repr(C)]
80pub struct RootedVFTable {
81 #[cfg(windows)]
82 pub padding: [usize; 1],
83 #[cfg(not(windows))]
84 pub padding: [usize; 2],
85 pub trace: unsafe extern "C" fn(this: *mut c_void, trc: *mut JSTracer, name: *const c_char),
86}
87
88impl RootedVFTable {
89 #[cfg(windows)]
90 pub const PADDING: [usize; 1] = [0];
91 #[cfg(not(windows))]
92 pub const PADDING: [usize; 2] = [0, 0];
93}
94
95pub trait Rootable: crate::trace::Traceable + Sized {
101 const VTABLE: RootedVFTable = RootedVFTable {
102 padding: RootedVFTable::PADDING,
103 trace: <Self as Rootable>::trace,
104 };
105
106 unsafe extern "C" fn trace(this: *mut c_void, trc: *mut JSTracer, _name: *const c_char) {
107 let rooted = this as *mut Rooted<Self>;
108 let rooted = rooted.as_mut().unwrap();
109 <Self as crate::trace::Traceable>::trace(&mut rooted.data, trc);
110 }
111}
112
113impl<T: Rootable> Rootable for Option<T> {}
114impl<T: crate::trace::Traceable> Rootable for Vec<T> {}
115impl<T: crate::trace::Traceable> Rootable for VecDeque<T> {}
116impl<T: crate::trace::Traceable> Rootable for Box<T> {}
117
118#[repr(C)]
125#[derive(Debug)]
126pub struct RootedBase {
127 pub stack: *mut *mut RootedBase,
128 pub prev: *mut RootedBase,
129}
130
131#[repr(C)]
133#[cfg_attr(
134 feature = "crown",
135 crown::unrooted_must_root_lint::allow_unrooted_interior
136)]
137pub struct Rooted<T: RootKind> {
138 pub vtable: T::Vtable,
139 pub base: RootedBase,
140 pub data: T,
141}
142
143pub trait Initialize: Sized {
145 unsafe fn initial() -> Option<Self>;
149}
150
151impl<T> Initialize for Option<T> {
152 unsafe fn initial() -> Option<Self> {
153 Some(None)
154 }
155}
156
157pub trait GCMethods: Initialize {
161 unsafe fn initial() -> Self {
163 <Self as Initialize>::initial()
164 .expect("Types used with heap GC methods must have a valid default")
165 }
166
167 unsafe fn post_barrier(v: *mut Self, prev: Self, next: Self);
169}
170
171impl Initialize for *mut JSObject {
172 unsafe fn initial() -> Option<*mut JSObject> {
173 Some(ptr::null_mut())
174 }
175}
176
177impl GCMethods for *mut JSObject {
178 unsafe fn post_barrier(v: *mut *mut JSObject, prev: *mut JSObject, next: *mut JSObject) {
179 JS::HeapObjectWriteBarriers(v, prev, next);
180 }
181}
182
183impl Initialize for *mut JSFunction {
184 unsafe fn initial() -> Option<*mut JSFunction> {
185 Some(ptr::null_mut())
186 }
187}
188
189impl GCMethods for *mut JSFunction {
190 unsafe fn post_barrier(v: *mut *mut JSFunction, prev: *mut JSFunction, next: *mut JSFunction) {
191 JS::HeapObjectWriteBarriers(
192 mem::transmute(v),
193 mem::transmute(prev),
194 mem::transmute(next),
195 );
196 }
197}
198
199impl Initialize for *mut JSString {
200 unsafe fn initial() -> Option<*mut JSString> {
201 Some(ptr::null_mut())
202 }
203}
204
205impl GCMethods for *mut JSString {
206 unsafe fn post_barrier(v: *mut *mut JSString, prev: *mut JSString, next: *mut JSString) {
207 JS::HeapStringWriteBarriers(v, prev, next);
208 }
209}
210
211impl Initialize for *mut JS::Symbol {
212 unsafe fn initial() -> Option<*mut JS::Symbol> {
213 Some(ptr::null_mut())
214 }
215}
216
217impl GCMethods for *mut JS::Symbol {
218 unsafe fn post_barrier(_: *mut *mut JS::Symbol, _: *mut JS::Symbol, _: *mut JS::Symbol) {}
219}
220
221impl Initialize for *mut JS::BigInt {
222 unsafe fn initial() -> Option<*mut JS::BigInt> {
223 Some(ptr::null_mut())
224 }
225}
226
227impl GCMethods for *mut JS::BigInt {
228 unsafe fn post_barrier(v: *mut *mut JS::BigInt, prev: *mut JS::BigInt, next: *mut JS::BigInt) {
229 JS::HeapBigIntWriteBarriers(v, prev, next);
230 }
231}
232
233impl Initialize for *mut JSScript {
234 unsafe fn initial() -> Option<*mut JSScript> {
235 Some(ptr::null_mut())
236 }
237}
238
239impl GCMethods for *mut JSScript {
240 unsafe fn post_barrier(v: *mut *mut JSScript, prev: *mut JSScript, next: *mut JSScript) {
241 JS::HeapScriptWriteBarriers(v, prev, next);
242 }
243}
244
245impl Initialize for jsid {
246 unsafe fn initial() -> Option<jsid> {
247 Some(VoidId())
248 }
249}
250
251impl GCMethods for jsid {
252 unsafe fn post_barrier(_: *mut jsid, _: jsid, _: jsid) {}
253}
254
255impl Initialize for JS::Value {
256 unsafe fn initial() -> Option<JS::Value> {
257 Some(JS::Value::default())
258 }
259}
260
261impl GCMethods for JS::Value {
262 unsafe fn post_barrier(v: *mut JS::Value, prev: JS::Value, next: JS::Value) {
263 JS::HeapValueWriteBarriers(v, &prev, &next);
264 }
265}
266
267impl Rootable for JS::PropertyDescriptor {}
268
269impl Initialize for JS::PropertyDescriptor {
270 unsafe fn initial() -> Option<JS::PropertyDescriptor> {
271 Some(JS::PropertyDescriptor::default())
272 }
273}
274
275impl GCMethods for JS::PropertyDescriptor {
276 unsafe fn post_barrier(
277 _: *mut JS::PropertyDescriptor,
278 _: JS::PropertyDescriptor,
279 _: JS::PropertyDescriptor,
280 ) {
281 }
282}
283
284pub struct ValueArray<const N: usize> {
288 elements: [JS::Value; N],
289}
290
291impl<const N: usize> ValueArray<N> {
292 pub fn new(elements: [JS::Value; N]) -> Self {
293 Self { elements }
294 }
295
296 pub fn get_ptr(&self) -> *const JS::Value {
297 self.elements.as_ptr()
298 }
299
300 pub unsafe fn get_mut_ptr(&self) -> *mut JS::Value {
301 self.elements.as_ptr() as *mut _
302 }
303}
304
305impl<const N: usize> Rootable for ValueArray<N> {}
306
307impl<const N: usize> Initialize for ValueArray<N> {
308 unsafe fn initial() -> Option<Self> {
309 Some(Self {
310 elements: [<JS::Value as GCMethods>::initial(); N],
311 })
312 }
313}
314
315pub type RootedValueArray<const N: usize> = Rooted<ValueArray<N>>;
317
318#[cfg_attr(feature = "crown", crown::unrooted_must_root_lint::must_root)]
333#[repr(C)]
334#[derive(Debug)]
335pub struct Heap<T: GCMethods + Copy> {
336 pub ptr: UnsafeCell<T>,
337}
338
339impl<T: GCMethods + Copy> Heap<T> {
340 #[cfg_attr(feature = "crown", expect(crown::unrooted_must_root))]
348 pub fn boxed(v: T) -> Box<Heap<T>>
349 where
350 Heap<T>: Default,
351 {
352 let boxed = Box::new(Heap::default());
353 boxed.set(v);
354 boxed
355 }
356
357 pub fn set(&self, v: T) {
358 unsafe {
359 let ptr = self.ptr.get();
360 let prev = *ptr;
361 *ptr = v;
362 T::post_barrier(ptr, prev, v);
363 }
364 }
365
366 pub fn get(&self) -> T {
367 unsafe { *self.ptr.get() }
368 }
369
370 pub fn get_unsafe(&self) -> *mut T {
371 self.ptr.get()
372 }
373
374 pub unsafe fn handle(&self) -> JS::Handle<T> {
388 JS::Handle::from_marked_location(self.ptr.get() as *const _)
389 }
390}
391
392impl<T> Default for Heap<*mut T>
393where
394 *mut T: GCMethods + Copy,
395{
396 fn default() -> Heap<*mut T> {
397 Heap {
398 ptr: UnsafeCell::new(ptr::null_mut()),
399 }
400 }
401}
402
403impl Default for Heap<JS::Value> {
404 fn default() -> Heap<JS::Value> {
405 Heap {
406 ptr: UnsafeCell::new(JS::Value::default()),
407 }
408 }
409}
410
411impl<T: GCMethods + Copy> Drop for Heap<T> {
412 fn drop(&mut self) {
413 unsafe {
414 let ptr = self.ptr.get();
415 T::post_barrier(ptr, *ptr, <T as GCMethods>::initial());
416 }
417 }
418}
419
420impl<T: GCMethods + Copy + PartialEq> PartialEq for Heap<T> {
421 fn eq(&self, other: &Self) -> bool {
422 self.get() == other.get()
423 }
424}
425
426pub trait IntoHandle {
431 type Target;
433
434 fn into_handle(self) -> JS::Handle<Self::Target>;
436}
437
438pub trait IntoMutableHandle: IntoHandle {
439 fn into_handle_mut(self) -> JS::MutableHandle<Self::Target>;
441}
442
443impl<T: IntoHandle> From<T> for JS::Handle<T::Target> {
444 fn from(value: T) -> Self {
445 value.into_handle()
446 }
447}
448
449impl<T: IntoMutableHandle> From<T> for JS::MutableHandle<T::Target> {
450 fn from(value: T) -> Self {
451 value.into_handle_mut()
452 }
453}
454
455#[repr(C)]
457pub struct CustomAutoRooterVFTable {
458 #[cfg(windows)]
459 pub padding: [usize; 1],
460 #[cfg(not(windows))]
461 pub padding: [usize; 2],
462 pub trace: unsafe extern "C" fn(this: *mut c_void, trc: *mut JSTracer),
463}
464
465impl CustomAutoRooterVFTable {
466 #[cfg(windows)]
467 pub const PADDING: [usize; 1] = [0];
468 #[cfg(not(windows))]
469 pub const PADDING: [usize; 2] = [0, 0];
470}
471
472#[repr(C)]
473#[derive(Copy, Clone)]
474pub struct StackGCVector<T, AllocPolicy = js::TempAllocPolicy>(PhantomData<(T, AllocPolicy)>, u8);