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