1use crate::Data;
4use crate::TracedReference;
5use crate::binding::RustObj;
6use crate::platform::Platform;
7use crate::support::Opaque;
8use crate::support::SharedRef;
9use crate::support::UniqueRef;
10use crate::support::int;
11use std::cell::UnsafeCell;
12use std::ffi::CStr;
13use std::ffi::c_char;
14use std::marker::PhantomData;
15use std::ptr::NonNull;
16
17unsafe extern "C" {
18 fn cppgc__initialize_process(platform: *mut Platform);
19 fn cppgc__shutdown_process();
20
21 fn v8__CppHeap__Create(
22 platform: *mut Platform,
23 marking_support: MarkingType,
24 sweeping_support: SweepingType,
25 ) -> *mut Heap;
26 fn v8__CppHeap__Terminate(heap: *mut Heap);
27 fn v8__CppHeap__DELETE(heap: *mut Heap);
28 fn cppgc__make_garbage_collectable(
29 heap: *mut Heap,
30 size: usize,
31 alignment: usize,
32 ) -> *mut RustObj;
33
34 fn cppgc__heap__enable_detached_garbage_collections_for_testing(
35 heap: *mut Heap,
36 );
37 fn cppgc__heap__collect_garbage_for_testing(
38 heap: *mut Heap,
39 stack_state: EmbedderStackState,
40 );
41
42 fn cppgc__Visitor__Trace__Member(
43 visitor: *mut Visitor,
44 member: *const MemberInner,
45 );
46 fn cppgc__Visitor__Trace__WeakMember(
47 visitor: *mut Visitor,
48 member: *const WeakMemberInner,
49 );
50 fn cppgc__Visitor__Trace__TracedReference(
51 visitor: *mut Visitor,
52 reference: *const TracedReference<Data>,
53 );
54
55 fn cppgc__Member__CONSTRUCT(member: *mut MemberInner, obj: *mut RustObj);
56 fn cppgc__Member__DESTRUCT(member: *mut MemberInner);
57 fn cppgc__Member__Get(member: *const MemberInner) -> *mut RustObj;
58 fn cppgc__Member__Assign(member: *mut MemberInner, other: *mut RustObj);
59
60 fn cppgc__WeakMember__CONSTRUCT(
61 member: *mut WeakMemberInner,
62 obj: *mut RustObj,
63 );
64 fn cppgc__WeakMember__DESTRUCT(member: *mut WeakMemberInner);
65 fn cppgc__WeakMember__Get(member: *const WeakMemberInner) -> *mut RustObj;
66 fn cppgc__WeakMember__Assign(
67 member: *mut WeakMemberInner,
68 other: *mut RustObj,
69 );
70
71 fn cppgc__Persistent__CONSTRUCT(obj: *mut RustObj) -> *mut PersistentInner;
72 fn cppgc__Persistent__DESTRUCT(this: *mut PersistentInner);
73 fn cppgc__Persistent__Assign(this: *mut PersistentInner, ptr: *mut RustObj);
74 fn cppgc__Persistent__Get(this: *const PersistentInner) -> *mut RustObj;
75
76 fn cppgc__WeakPersistent__CONSTRUCT(
77 obj: *mut RustObj,
78 ) -> *mut WeakPersistentInner;
79 fn cppgc__WeakPersistent__DESTRUCT(this: *mut WeakPersistentInner);
80 fn cppgc__WeakPersistent__Assign(
81 this: *mut WeakPersistentInner,
82 ptr: *mut RustObj,
83 );
84 fn cppgc__WeakPersistent__Get(
85 this: *const WeakPersistentInner,
86 ) -> *mut RustObj;
87}
88
89#[unsafe(no_mangle)]
90unsafe extern "C" fn rusty_v8_RustObj_trace(
91 obj: *const RustObj,
92 visitor: *mut Visitor,
93) {
94 unsafe {
95 let r = get_rust_obj(obj);
96 r.trace(&mut *visitor);
97 }
98}
99
100#[unsafe(no_mangle)]
101unsafe extern "C" fn rusty_v8_RustObj_get_name(
102 obj: *const RustObj,
103) -> *const c_char {
104 let r = unsafe { get_rust_obj(obj) };
105 r.get_name().as_ptr()
106}
107
108#[unsafe(no_mangle)]
109unsafe extern "C" fn rusty_v8_RustObj_drop(obj: *mut RustObj) {
110 unsafe {
111 let r = get_rust_obj_mut(obj);
112 std::ptr::drop_in_place(r);
113 }
114}
115
116pub fn initialize_process(platform: SharedRef<Platform>) {
121 unsafe {
122 cppgc__initialize_process(&*platform as *const Platform as *mut _);
123 }
124}
125
126pub unsafe fn shutdown_process() {
132 unsafe {
133 cppgc__shutdown_process();
134 }
135}
136
137#[repr(C)]
157#[derive(Debug)]
158pub struct Visitor(Opaque);
159
160impl Visitor {
161 #[inline(always)]
163 pub fn trace(&mut self, member: &impl Traced) {
164 member.trace(self);
165 }
166}
167
168pub trait Traced {
171 fn trace(&self, visitor: &mut Visitor);
173}
174
175impl<T: Traced> Traced for Option<T> {
176 fn trace(&self, visitor: &mut Visitor) {
177 if let Some(value) = self {
178 visitor.trace(value);
179 }
180 }
181}
182
183impl<T> Traced for TracedReference<T> {
184 fn trace(&self, visitor: &mut Visitor) {
185 unsafe {
186 cppgc__Visitor__Trace__TracedReference(
187 visitor,
188 self as *const TracedReference<T> as *const TracedReference<Data>,
189 );
190 }
191 }
192}
193
194#[repr(C)]
195pub enum EmbedderStackState {
196 MayContainHeapPointers,
198 NoHeapPointers,
200}
201
202#[repr(u8)]
204pub enum MarkingType {
205 Atomic,
207 Incremental,
209 IncrementalAndConcurrent,
211}
212
213#[repr(u8)]
215pub enum SweepingType {
216 Atomic,
218 Incremental,
220 IncrementalAndConcurrent,
222}
223
224pub type InternalFieldIndex = int;
225
226pub struct HeapCreateParams {
227 pub marking_support: MarkingType,
229 pub sweeping_support: SweepingType,
231}
232
233impl Default for HeapCreateParams {
234 fn default() -> Self {
235 Self {
236 marking_support: MarkingType::IncrementalAndConcurrent,
237 sweeping_support: SweepingType::IncrementalAndConcurrent,
238 }
239 }
240}
241
242#[repr(C)]
247#[derive(Debug)]
248pub struct Heap(Opaque);
249
250impl Drop for Heap {
251 fn drop(&mut self) {
252 unsafe {
253 v8__CppHeap__DELETE(self);
254 }
255 }
256}
257
258impl Heap {
259 pub fn create(
260 platform: SharedRef<Platform>,
261 params: HeapCreateParams,
262 ) -> UniqueRef<Heap> {
263 unsafe {
264 UniqueRef::from_raw(v8__CppHeap__Create(
265 &*platform as *const Platform as *mut _,
266 params.marking_support,
267 params.sweeping_support,
268 ))
269 }
270 }
271
272 pub unsafe fn collect_garbage_for_testing(
273 &self,
274 stack_state: EmbedderStackState,
275 ) {
276 unsafe {
277 cppgc__heap__collect_garbage_for_testing(
278 self as *const Heap as *mut _,
279 stack_state,
280 );
281 }
282 }
283
284 pub fn enable_detached_garbage_collections_for_testing(&self) {
285 unsafe {
286 cppgc__heap__enable_detached_garbage_collections_for_testing(
287 self as *const Heap as *mut _,
288 );
289 }
290 }
291
292 pub fn terminate(&mut self) {
293 unsafe {
294 v8__CppHeap__Terminate(self);
295 }
296 }
297}
298
299pub unsafe trait GarbageCollected {
308 fn trace(&self, visitor: &mut Visitor);
312
313 fn get_name(&self) -> &'static CStr;
323}
324
325#[repr(C)]
326struct RustObjConcrete<T> {
327 head: RustObj,
328 dynamic: *mut dyn GarbageCollected,
329 value: T,
330}
331
332unsafe fn get_rust_obj<'s>(obj: *const RustObj) -> &'s dyn GarbageCollected {
333 unsafe {
334 let obj = &*(obj as *const RustObjConcrete<()>);
335 &*obj.dynamic
336 }
337}
338
339unsafe fn get_rust_obj_mut<'s>(
340 obj: *mut RustObj,
341) -> &'s mut dyn GarbageCollected {
342 unsafe {
343 let obj = &mut *(obj as *mut RustObjConcrete<()>);
344 &mut *obj.dynamic
345 }
346}
347
348pub unsafe fn make_garbage_collected<T: GarbageCollected + 'static>(
361 heap: &Heap,
362 obj: T,
363) -> UnsafePtr<T> {
364 const {
365 assert!(std::mem::align_of::<T>() <= 16);
367 assert!(
368 std::mem::offset_of!(RustObjConcrete<T>, dynamic)
369 == std::mem::offset_of!(RustObjConcrete<()>, dynamic)
370 );
371 }
372
373 let additional_bytes =
374 std::mem::size_of::<RustObjConcrete<T>>() - std::mem::size_of::<RustObj>();
375
376 let pointer = unsafe {
377 cppgc__make_garbage_collectable(
378 heap as *const Heap as *mut _,
379 additional_bytes,
380 std::mem::align_of::<RustObjConcrete<T>>(),
381 )
382 };
383
384 assert!(!pointer.is_null());
385
386 unsafe {
387 let pointer = &mut *(pointer as *mut RustObjConcrete<T>);
388 let value_ptr = std::ptr::addr_of_mut!(pointer.value);
389 value_ptr.write(obj);
390 std::ptr::addr_of_mut!(pointer.dynamic).write(value_ptr as _);
391 }
392
393 UnsafePtr {
394 pointer: unsafe { NonNull::new_unchecked(pointer) },
395 _phantom: PhantomData,
396 }
397}
398
399unsafe fn get_value_from_rust_obj<T: GarbageCollected>(
403 obj: *mut RustObj,
404) -> *const T {
405 unsafe {
406 let obj = &mut *(obj as *mut RustObjConcrete<T>);
407 std::ptr::addr_of_mut!(obj.value)
408 }
409}
410
411#[derive(Clone, Copy)]
413pub struct UnsafePtr<T: GarbageCollected> {
414 pointer: NonNull<RustObj>,
415 _phantom: PhantomData<T>,
416}
417
418impl<T: GarbageCollected> UnsafePtr<T> {
419 pub unsafe fn new(value: &impl GetRustObj<T>) -> Option<UnsafePtr<T>> {
426 NonNull::new(value.get_rust_obj()).map(|pointer| UnsafePtr {
427 pointer,
428 _phantom: PhantomData,
429 })
430 }
431
432 pub unsafe fn as_ref(&self) -> &T {
433 unsafe { &*get_value_from_rust_obj(self.pointer.as_ptr()) }
434 }
435}
436
437impl<T: GarbageCollected> GetRustObj<T> for UnsafePtr<T> {
438 fn get_rust_obj(&self) -> *mut RustObj {
439 self.pointer.as_ptr()
440 }
441}
442
443#[doc(hidden)]
444pub trait GetRustObj<T: GarbageCollected> {
445 fn get_rust_obj(&self) -> *mut RustObj;
446}
447
448impl<T: GarbageCollected> GetRustObj<T> for *mut RustObj {
449 fn get_rust_obj(&self) -> *mut RustObj {
450 *self
451 }
452}
453
454macro_rules! member {
455 ($( # $attr:tt )* $name:ident) => {
456 paste::paste! {
457 #[repr(transparent)]
458 struct [< $name Inner >]([u8; crate::binding:: [< cppgc__ $name _SIZE >]]);
459
460 impl [< $name Inner >] {
461 fn new(ptr: *mut RustObj) -> Self {
462 let mut this = std::mem::MaybeUninit::uninit();
463 unsafe {
464 [< cppgc__ $name __CONSTRUCT >](this.as_mut_ptr(), ptr);
465 this.assume_init()
466 }
467 }
468
469 #[inline(always)]
470 fn get(&self) -> *mut RustObj {
471 unsafe { [< cppgc__ $name __Get >](self) }
473 }
474
475 #[inline(always)]
476 fn assign(&mut self, ptr: *mut RustObj) {
477 unsafe {
479 [< cppgc__ $name __Assign >](self, ptr);
480 }
481 }
482 }
483
484 impl Drop for [< $name Inner >] {
485 fn drop(&mut self) {
486 unsafe {
487 [< cppgc__ $name __DESTRUCT >](self);
488 }
489 }
490 }
491
492 $( # $attr )*
493 #[repr(transparent)]
494 pub struct $name<T: GarbageCollected> {
495 inner: [< $name Inner >],
496 _phantom: PhantomData<T>,
497 }
498
499 impl<T: GarbageCollected> $name<T> {
500 #[doc = "Create a new empty "]
501 #[doc = stringify!($name)]
502 #[doc = " which may be set later."]
503 pub fn empty() -> Self {
504 Self {
505 inner: [< $name Inner >]::new(std::ptr::null_mut()),
506 _phantom: PhantomData,
507 }
508 }
509
510 #[doc = "Create a new "]
511 #[doc = stringify!($name)]
512 #[doc = " and initialize it with an object."]
513 pub fn new(other: &impl GetRustObj<T>) -> Self {
514 Self {
515 inner: [< $name Inner >]::new(other.get_rust_obj()),
516 _phantom: PhantomData,
517 }
518 }
519
520 #[doc = "Set the object pointed to by this "]
521 #[doc = stringify!($name)]
522 #[doc = "."]
523 pub fn set(&mut self, other: &impl GetRustObj<T>) {
524 let ptr = other.get_rust_obj();
525 self.inner.assign(ptr);
526 }
527
528 #[doc = "Get the object pointed to by this "]
529 #[doc = stringify!($name)]
530 #[doc = ", returning `None` if the pointer is empty or has been garbage-collected."]
531 #[doc = ""]
532 #[doc = "# Safety"]
533 #[doc = ""]
534 #[doc = "The caller must ensure that this pointer is being traced correctly by appearing in the [`trace`](GarbageCollected::trace)"]
535 #[doc = "implementation of the object that owns the pointer. Between initializing the pointer and calling `get()`, the pointer must be reachable by the garbage collector."]
536 pub unsafe fn get(&self) -> Option<&T> {
537 let ptr = self.inner.get();
538 if ptr.is_null() {
539 None
540 } else {
541 Some(unsafe { &*get_value_from_rust_obj(ptr) })
545 }
546 }
547 }
548
549 impl<T: GarbageCollected> GetRustObj<T> for $name<T> {
550 fn get_rust_obj(&self) -> *mut RustObj {
551 self.inner.get()
552 }
553 }
554
555 impl<T: GarbageCollected> Traced for $name<T> {
556 fn trace(&self, visitor: &mut Visitor) {
557 unsafe { [< cppgc__Visitor__Trace__ $name >](visitor, &self.inner) }
558 }
559 }
560
561 impl<T: GarbageCollected> std::fmt::Debug for $name<T> {
562 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
563 fmt.debug_struct(stringify!($name)).finish()
564 }
565 }
566 }
567 }
568}
569
570member! {
571 Member
575}
576
577member! {
578 WeakMember
585}
586
587macro_rules! persistent {
588 ($( # $attr:tt )* $name:ident) => {
589 paste::paste! {
590 #[repr(C)]
593 struct [< $name Inner >](Opaque);
594
595 $( # $attr )*
596 pub struct $name<T: GarbageCollected> {
597 inner: *mut [< $name Inner >],
598 _phantom: PhantomData<T>,
599 }
600
601 impl<T: GarbageCollected> $name<T> {
602 #[doc = "Create a new empty "]
603 #[doc = stringify!($name)]
604 #[doc = " which may be set later."]
605 pub fn empty() -> Self {
606 let this = unsafe { [< cppgc__ $name __CONSTRUCT >](std::ptr::null_mut()) };
607 Self {
608 inner: this,
609 _phantom: PhantomData,
610 }
611 }
612
613 #[doc = "Create a new "]
614 #[doc = stringify!($name)]
615 #[doc = " and initialize it with an object."]
616 pub fn new(other: &impl GetRustObj<T>) -> Self {
617 let this = unsafe { [< cppgc__ $name __CONSTRUCT >](other.get_rust_obj()) };
618 Self {
619 inner: this,
620 _phantom: PhantomData,
621 }
622 }
623
624 #[doc = "Set the object pointed to by this "]
625 #[doc = stringify!($name)]
626 #[doc = "."]
627 pub fn set(&mut self, other: &impl GetRustObj<T>) {
628 let ptr = other.get_rust_obj();
629 self.assign(ptr);
630 }
631
632 #[doc = "Borrow the object pointed to by this "]
633 #[doc = stringify!($name)]
634 #[doc = "."]
635 pub fn get(&self) -> Option<&T> {
636 let ptr = self.get_rust_obj();
637 if ptr.is_null() {
638 None
639 } else {
640 Some(unsafe { &*get_value_from_rust_obj(ptr) })
643 }
644 }
645
646 #[inline(always)]
647 fn assign(&mut self, ptr: *mut RustObj) {
648 unsafe {
649 [< cppgc__ $name __Assign >](self.inner, ptr);
650 }
651 }
652 }
653
654 impl<T: GarbageCollected> Drop for $name<T> {
655 fn drop(&mut self) {
656 unsafe {
657 [< cppgc__ $name __DESTRUCT >](self.inner);
658 }
659 }
660 }
661
662 impl<T: GarbageCollected> std::fmt::Debug for $name<T> {
663 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
664 fmt.debug_struct(stringify!($name)).finish()
665 }
666 }
667
668 impl<T: GarbageCollected> GetRustObj<T> for $name<T> {
669 fn get_rust_obj(&self) -> *mut RustObj {
670 unsafe {
671 [< cppgc__ $name __Get >](self.inner)
672 }
673 }
674 }
675 }
676 };
677}
678
679persistent! {
680 Persistent
686}
687
688persistent! {
689 WeakPersistent
694}
695
696pub struct GcCell<T> {
712 value: UnsafeCell<T>,
714}
715
716impl<T> std::fmt::Debug for GcCell<T> {
717 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
718 f.debug_struct("GcCell").finish()
719 }
720}
721
722unsafe impl<T: Send> Send for GcCell<T> {}
723unsafe impl<T: Sync> Sync for GcCell<T> {}
724
725impl<T> GcCell<T> {
726 pub fn new(value: T) -> Self {
727 Self {
728 value: UnsafeCell::new(value),
729 }
730 }
731
732 pub fn set(&self, isolate: &mut crate::Isolate, value: T) {
733 _ = isolate;
734 unsafe {
735 *self.value.get() = value;
738 }
739 }
740}
741
742impl<T> GcCell<T> {
743 pub fn get<'a>(&'a self, isolate: &'a crate::Isolate) -> &'a T {
744 _ = isolate;
745 unsafe {
746 &*self.value.get()
749 }
750 }
751
752 pub fn get_mut<'a>(&'a self, isolate: &'a mut crate::Isolate) -> &'a mut T {
753 _ = isolate;
754 unsafe {
755 &mut *self.value.get()
758 }
759 }
760
761 pub fn with<'a, 's, R>(
762 &'a self,
763 scope: &'a mut crate::HandleScope<'s>,
764 f: impl FnOnce(&'a mut crate::HandleScope<'s>, &'a mut T) -> R,
765 ) -> R {
766 f(scope, unsafe { &mut *self.value.get() })
767 }
768}
769
770impl<T: Traced> Traced for GcCell<T> {
771 fn trace(&self, visitor: &mut Visitor) {
772 unsafe {
773 visitor.trace(&(*self.value.get()));
776 }
777 }
778}