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