diff --git a/src/binding.cc b/src/binding.cc index 9932f78f4d..3753c03200 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -3816,21 +3816,24 @@ extern "C" { class RustObj; -using RustTraceFn = void (*)(const RustObj* obj, cppgc::Visitor*); -using RustDestroyFn = void (*)(const RustObj* obj); +void rusty_v8_RustObj_trace(const RustObj*, cppgc::Visitor*); +const char* rusty_v8_RustObj_get_name(const RustObj*); +void rusty_v8_RustObj_drop(RustObj*); -class RustObj final : public cppgc::GarbageCollected { +class RustObj final : public cppgc::GarbageCollected, + public cppgc::NameProvider { public: - explicit RustObj(RustTraceFn trace, RustDestroyFn destroy) - : trace_(trace), destroy_(destroy) {} + ~RustObj() { rusty_v8_RustObj_drop(this); } - ~RustObj() { destroy_(this); } + void Trace(cppgc::Visitor* visitor) const { + rusty_v8_RustObj_trace(this, visitor); + } - void Trace(cppgc::Visitor* visitor) const { trace_(this, visitor); } + const char* GetHumanReadableName() const final { + return rusty_v8_RustObj_get_name(this); + } - private: - RustTraceFn trace_; - RustDestroyFn destroy_; + uintptr_t data[2]; }; RustObj* v8__Object__Unwrap(v8::Isolate* isolate, const v8::Object& wrapper, @@ -3878,12 +3881,9 @@ void cppgc__heap__collect_garbage_for_testing( heap->CollectGarbageForTesting(stack_state); } -RustObj* cppgc__make_garbage_collectable(v8::CppHeap* heap, size_t size, - RustTraceFn trace, - RustDestroyFn destroy) { +RustObj* cppgc__make_garbage_collectable(v8::CppHeap* heap, size_t size) { return cppgc::MakeGarbageCollected(heap->GetAllocationHandle(), - cppgc::AdditionalBytes(size), - trace, destroy); + cppgc::AdditionalBytes(size)); } void cppgc__Visitor__Trace__Member(cppgc::Visitor* visitor, diff --git a/src/cppgc.rs b/src/cppgc.rs index 4405b25ac9..26dd47b6d1 100644 --- a/src/cppgc.rs +++ b/src/cppgc.rs @@ -7,6 +7,8 @@ use crate::support::SharedRef; use crate::support::UniqueRef; use crate::Data; use crate::TracedReference; +use std::ffi::c_char; +use std::ffi::CStr; use std::marker::PhantomData; use std::ptr::NonNull; @@ -20,11 +22,10 @@ extern "C" { sweeping_support: SweepingType, ) -> *mut Heap; fn cppgc__heap__DELETE(heap: *mut Heap); + #[allow(improper_ctypes)] fn cppgc__make_garbage_collectable( heap: *mut Heap, size: usize, - trace: TraceFn, - destroy: DestroyFn, ) -> *mut RustObj; fn cppgc__heap__enable_detached_garbage_collections_for_testing( @@ -48,48 +49,92 @@ extern "C" { reference: *const TracedReference, ); + #[allow(improper_ctypes)] fn cppgc__Member__CONSTRUCT(member: *mut MemberInner, obj: *mut RustObj); fn cppgc__Member__DESTRUCT(member: *mut MemberInner); + #[allow(improper_ctypes)] fn cppgc__Member__Get(member: *const MemberInner) -> *mut RustObj; + #[allow(improper_ctypes)] fn cppgc__Member__Assign(member: *mut MemberInner, other: *mut RustObj); + #[allow(improper_ctypes)] fn cppgc__WeakMember__CONSTRUCT( member: *mut WeakMemberInner, obj: *mut RustObj, ); fn cppgc__WeakMember__DESTRUCT(member: *mut WeakMemberInner); + #[allow(improper_ctypes)] fn cppgc__WeakMember__Get(member: *const WeakMemberInner) -> *mut RustObj; + #[allow(improper_ctypes)] fn cppgc__WeakMember__Assign( member: *mut WeakMemberInner, other: *mut RustObj, ); + #[allow(improper_ctypes)] fn cppgc__Persistent__CONSTRUCT(obj: *mut RustObj) -> *mut PersistentInner; fn cppgc__Persistent__DESTRUCT(this: *mut PersistentInner); + #[allow(improper_ctypes)] fn cppgc__Persistent__Assign(this: *mut PersistentInner, ptr: *mut RustObj); + #[allow(improper_ctypes)] fn cppgc__Persistent__Get(this: *const PersistentInner) -> *mut RustObj; + #[allow(improper_ctypes)] fn cppgc__WeakPersistent__CONSTRUCT( obj: *mut RustObj, ) -> *mut WeakPersistentInner; fn cppgc__WeakPersistent__DESTRUCT(this: *mut WeakPersistentInner); + #[allow(improper_ctypes)] fn cppgc__WeakPersistent__Assign( this: *mut WeakPersistentInner, ptr: *mut RustObj, ); + #[allow(improper_ctypes)] fn cppgc__WeakPersistent__Get( this: *const WeakPersistentInner, ) -> *mut RustObj; } -type TraceFn = unsafe extern "C" fn(*const RustObj, *mut Visitor); -type DestroyFn = unsafe extern "C" fn(*const RustObj); - #[doc(hidden)] #[repr(C)] pub struct RustObj { - trace: TraceFn, - destroy: DestroyFn, + data: *mut dyn GarbageCollected, +} + +unsafe fn get_dyn<'s>(obj: *mut RustObj) -> &'s mut dyn GarbageCollected { + const { + assert!( + std::mem::size_of::<*mut dyn GarbageCollected>() + == std::mem::size_of::<[usize; 2]>() + ); + } + &mut *(*obj).data +} + +#[no_mangle] +unsafe extern "C" fn rusty_v8_RustObj_trace( + obj: *mut RustObj, + visitor: *mut Visitor, +) { + let r = get_dyn(obj); + r.trace(&*visitor); +} + +#[no_mangle] +unsafe extern "C" fn rusty_v8_RustObj_get_name( + obj: *mut RustObj, +) -> *const c_char { + let r = get_dyn(obj); + match r.get_name() { + Some(s) => s.as_ptr(), + None => std::ptr::null(), + } +} + +#[no_mangle] +unsafe extern "C" fn rusty_v8_RustObj_drop(obj: *mut RustObj) { + let r = get_dyn(obj); + std::ptr::drop_in_place(r); } fn object_offset_for_rust_obj() -> usize { @@ -102,7 +147,10 @@ fn object_offset_for_rust_obj() -> usize { std::mem::offset_of!(Calc, data) } -fn get_object_from_rust_obj( +/// # Safety +/// +/// T must be the correct type for this specific RustObj +unsafe fn get_object_from_rust_obj( rust_obj: *const RustObj, ) -> *mut T { unsafe { rust_obj.byte_add(object_offset_for_rust_obj::()) as *mut T } @@ -267,7 +315,23 @@ impl Heap { /// Base trait for managed objects. pub trait GarbageCollected { + /// `trace` should call `Visitor::visit` for each + /// `Member`, `WeakMember`, or `TracedReference` in + /// by the managed object. fn trace(&self, _visitor: &Visitor) {} + + /// Specifies a name for the garbage-collected object. Such names will never + /// be hidden, as they are explicitly specified by the user of this API. + /// + /// V8 may call this function while generating a heap snapshot or at other + /// times. If V8 is currently generating a heap snapshot (according to + /// HeapProfiler::IsTakingSnapshot), then the returned string must stay alive + /// until the snapshot generation has completed. Otherwise, the returned string + /// must stay alive forever. If you need a place to store a temporary string + /// during snapshot generation, use HeapProfiler::CopyNameForHeapSnapshot. + fn get_name(&self) -> Option<&'static CStr> { + None + } } /// Constructs an instance of T, which is a garbage collected type. @@ -282,23 +346,10 @@ pub trait GarbageCollected { /// /// The caller must ensure that the returned pointer is always stored on /// the stack, or is safely moved into one of the other cppgc pointer types. -pub unsafe fn make_garbage_collected( +pub unsafe fn make_garbage_collected( heap: &Heap, obj: T, ) -> Ptr { - unsafe extern "C" fn trace( - obj: *const RustObj, - visitor: *mut Visitor, - ) { - let obj = unsafe { &*get_object_from_rust_obj::(obj) }; - obj.trace(unsafe { &*visitor }); - } - - unsafe extern "C" fn destroy(obj: *const RustObj) { - let obj = get_object_from_rust_obj::(obj); - std::ptr::drop_in_place(obj); - } - let additional_bytes = (object_offset_for_rust_obj::() - std::mem::size_of::()) + std::mem::size_of::(); @@ -307,13 +358,16 @@ pub unsafe fn make_garbage_collected( cppgc__make_garbage_collectable( heap as *const Heap as *mut _, additional_bytes, - trace::, - destroy::, ) }; unsafe { - get_object_from_rust_obj::(pointer).write(obj); + let inner = get_object_from_rust_obj::(pointer); + inner.write(obj); + + let rust_obj = &mut *pointer; + rust_obj.data = + (&mut *inner) as &mut dyn GarbageCollected as *mut dyn GarbageCollected; } Ptr { diff --git a/src/object.rs b/src/object.rs index b0d6fe07c5..ed4c6326d4 100644 --- a/src/object.rs +++ b/src/object.rs @@ -213,12 +213,14 @@ extern "C" { key: *const Name, out: *mut Maybe, ); + #[allow(improper_ctypes)] fn v8__Object__Wrap( isolate: *const Isolate, wrapper: *const Object, value: *const RustObj, tag: u16, ); + #[allow(improper_ctypes)] fn v8__Object__Unwrap( isolate: *const Isolate, wrapper: *const Object, diff --git a/tests/test_cppgc.rs b/tests/test_cppgc.rs index 66e6573f97..2c12fa0c97 100644 --- a/tests/test_cppgc.rs +++ b/tests/test_cppgc.rs @@ -44,6 +44,10 @@ fn cppgc_object_wrap() { TRACE_COUNT.fetch_add(1, Ordering::SeqCst); visitor.trace(&self.value); } + + fn get_name(&self) -> Option<&'static std::ffi::CStr> { + Some(c"Wrap") + } } impl Drop for Wrap {