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