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> {}
116
117#[repr(C)]
124#[derive(Debug)]
125pub struct RootedBase {
126 pub stack: *mut *mut RootedBase,
127 pub prev: *mut RootedBase,
128}
129
130#[repr(C)]
132#[cfg_attr(
133 feature = "crown",
134 crown::unrooted_must_root_lint::allow_unrooted_interior
135)]
136pub struct Rooted<T: RootKind> {
137 pub vtable: T::Vtable,
138 pub base: RootedBase,
139 pub data: T,
140}
141
142pub trait Initialize: Sized {
144 unsafe fn initial() -> Option<Self>;
148}
149
150impl<T> Initialize for Option<T> {
151 unsafe fn initial() -> Option<Self> {
152 Some(None)
153 }
154}
155
156pub trait GCMethods: Initialize {
160 unsafe fn initial() -> Self {
162 <Self as Initialize>::initial()
163 .expect("Types used with heap GC methods must have a valid default")
164 }
165
166 unsafe fn post_barrier(v: *mut Self, prev: Self, next: Self);
168}
169
170impl Initialize for *mut JSObject {
171 unsafe fn initial() -> Option<*mut JSObject> {
172 Some(ptr::null_mut())
173 }
174}
175
176impl GCMethods for *mut JSObject {
177 unsafe fn post_barrier(v: *mut *mut JSObject, prev: *mut JSObject, next: *mut JSObject) {
178 JS::HeapObjectWriteBarriers(v, prev, next);
179 }
180}
181
182impl Initialize for *mut JSFunction {
183 unsafe fn initial() -> Option<*mut JSFunction> {
184 Some(ptr::null_mut())
185 }
186}
187
188impl GCMethods for *mut JSFunction {
189 unsafe fn post_barrier(v: *mut *mut JSFunction, prev: *mut JSFunction, next: *mut JSFunction) {
190 JS::HeapObjectWriteBarriers(
191 mem::transmute(v),
192 mem::transmute(prev),
193 mem::transmute(next),
194 );
195 }
196}
197
198impl Initialize for *mut JSString {
199 unsafe fn initial() -> Option<*mut JSString> {
200 Some(ptr::null_mut())
201 }
202}
203
204impl GCMethods for *mut JSString {
205 unsafe fn post_barrier(v: *mut *mut JSString, prev: *mut JSString, next: *mut JSString) {
206 JS::HeapStringWriteBarriers(v, prev, next);
207 }
208}
209
210impl Initialize for *mut JS::Symbol {
211 unsafe fn initial() -> Option<*mut JS::Symbol> {
212 Some(ptr::null_mut())
213 }
214}
215
216impl GCMethods for *mut JS::Symbol {
217 unsafe fn post_barrier(_: *mut *mut JS::Symbol, _: *mut JS::Symbol, _: *mut JS::Symbol) {}
218}
219
220impl Initialize for *mut JS::BigInt {
221 unsafe fn initial() -> Option<*mut JS::BigInt> {
222 Some(ptr::null_mut())
223 }
224}
225
226impl GCMethods for *mut JS::BigInt {
227 unsafe fn post_barrier(v: *mut *mut JS::BigInt, prev: *mut JS::BigInt, next: *mut JS::BigInt) {
228 JS::HeapBigIntWriteBarriers(v, prev, next);
229 }
230}
231
232impl Initialize for *mut JSScript {
233 unsafe fn initial() -> Option<*mut JSScript> {
234 Some(ptr::null_mut())
235 }
236}
237
238impl GCMethods for *mut JSScript {
239 unsafe fn post_barrier(v: *mut *mut JSScript, prev: *mut JSScript, next: *mut JSScript) {
240 JS::HeapScriptWriteBarriers(v, prev, next);
241 }
242}
243
244impl Initialize for jsid {
245 unsafe fn initial() -> Option<jsid> {
246 Some(VoidId())
247 }
248}
249
250impl GCMethods for jsid {
251 unsafe fn post_barrier(_: *mut jsid, _: jsid, _: jsid) {}
252}
253
254impl Initialize for JS::Value {
255 unsafe fn initial() -> Option<JS::Value> {
256 Some(JS::Value::default())
257 }
258}
259
260impl GCMethods for JS::Value {
261 unsafe fn post_barrier(v: *mut JS::Value, prev: JS::Value, next: JS::Value) {
262 JS::HeapValueWriteBarriers(v, &prev, &next);
263 }
264}
265
266impl Rootable for JS::PropertyDescriptor {}
267
268impl Initialize for JS::PropertyDescriptor {
269 unsafe fn initial() -> Option<JS::PropertyDescriptor> {
270 Some(JS::PropertyDescriptor::default())
271 }
272}
273
274impl GCMethods for JS::PropertyDescriptor {
275 unsafe fn post_barrier(
276 _: *mut JS::PropertyDescriptor,
277 _: JS::PropertyDescriptor,
278 _: JS::PropertyDescriptor,
279 ) {
280 }
281}
282
283pub struct ValueArray<const N: usize> {
287 elements: [JS::Value; N],
288}
289
290impl<const N: usize> ValueArray<N> {
291 pub fn new(elements: [JS::Value; N]) -> Self {
292 Self { elements }
293 }
294
295 pub fn get_ptr(&self) -> *const JS::Value {
296 self.elements.as_ptr()
297 }
298
299 pub unsafe fn get_mut_ptr(&self) -> *mut JS::Value {
300 self.elements.as_ptr() as *mut _
301 }
302}
303
304impl<const N: usize> Rootable for ValueArray<N> {}
305
306impl<const N: usize> Initialize for ValueArray<N> {
307 unsafe fn initial() -> Option<Self> {
308 Some(Self {
309 elements: [<JS::Value as GCMethods>::initial(); N],
310 })
311 }
312}
313
314pub type RootedValueArray<const N: usize> = Rooted<ValueArray<N>>;
316
317#[cfg_attr(feature = "crown", crown::unrooted_must_root_lint::must_root)]
332#[repr(C)]
333#[derive(Debug)]
334pub struct Heap<T: GCMethods + Copy> {
335 pub ptr: UnsafeCell<T>,
336}
337
338impl<T: GCMethods + Copy> Heap<T> {
339 #[cfg_attr(feature = "crown", expect(crown::unrooted_must_root))]
347 pub fn boxed(v: T) -> Box<Heap<T>>
348 where
349 Heap<T>: Default,
350 {
351 let boxed = Box::new(Heap::default());
352 boxed.set(v);
353 boxed
354 }
355
356 pub fn set(&self, v: T) {
357 unsafe {
358 let ptr = self.ptr.get();
359 let prev = *ptr;
360 *ptr = v;
361 T::post_barrier(ptr, prev, v);
362 }
363 }
364
365 pub fn get(&self) -> T {
366 unsafe { *self.ptr.get() }
367 }
368
369 pub fn get_unsafe(&self) -> *mut T {
370 self.ptr.get()
371 }
372
373 pub unsafe fn handle(&self) -> JS::Handle<T> {
387 JS::Handle::from_marked_location(self.ptr.get() as *const _)
388 }
389}
390
391impl<T> Default for Heap<*mut T>
392where
393 *mut T: GCMethods + Copy,
394{
395 fn default() -> Heap<*mut T> {
396 Heap {
397 ptr: UnsafeCell::new(ptr::null_mut()),
398 }
399 }
400}
401
402impl Default for Heap<JS::Value> {
403 fn default() -> Heap<JS::Value> {
404 Heap {
405 ptr: UnsafeCell::new(JS::Value::default()),
406 }
407 }
408}
409
410impl<T: GCMethods + Copy> Drop for Heap<T> {
411 fn drop(&mut self) {
412 unsafe {
413 let ptr = self.ptr.get();
414 T::post_barrier(ptr, *ptr, <T as GCMethods>::initial());
415 }
416 }
417}
418
419impl<T: GCMethods + Copy + PartialEq> PartialEq for Heap<T> {
420 fn eq(&self, other: &Self) -> bool {
421 self.get() == other.get()
422 }
423}
424
425pub trait IntoHandle {
430 type Target;
432
433 fn into_handle(self) -> JS::Handle<Self::Target>;
435}
436
437pub trait IntoMutableHandle: IntoHandle {
438 fn into_handle_mut(self) -> JS::MutableHandle<Self::Target>;
440}
441
442impl<T: IntoHandle> From<T> for JS::Handle<T::Target> {
443 fn from(value: T) -> Self {
444 value.into_handle()
445 }
446}
447
448impl<T: IntoMutableHandle> From<T> for JS::MutableHandle<T::Target> {
449 fn from(value: T) -> Self {
450 value.into_handle_mut()
451 }
452}
453
454#[repr(C)]
456pub struct CustomAutoRooterVFTable {
457 #[cfg(windows)]
458 pub padding: [usize; 1],
459 #[cfg(not(windows))]
460 pub padding: [usize; 2],
461 pub trace: unsafe extern "C" fn(this: *mut c_void, trc: *mut JSTracer),
462}
463
464impl CustomAutoRooterVFTable {
465 #[cfg(windows)]
466 pub const PADDING: [usize; 1] = [0];
467 #[cfg(not(windows))]
468 pub const PADDING: [usize; 2] = [0, 0];
469}
470
471#[repr(C)]
472#[derive(Copy, Clone)]
473pub struct StackGCVector<T, AllocPolicy = js::TempAllocPolicy>(PhantomData<(T, AllocPolicy)>, u8);