feat: cppgc NameProvider (#1528)

This commit is contained in:
snek 2024-09-06 15:35:35 -07:00 committed by GitHub
parent 8a5f484c71
commit b2ef529146
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 105 additions and 50 deletions

View File

@ -157,6 +157,7 @@ fn build_binding() {
.rustified_enum(".*UseCounterFeature") .rustified_enum(".*UseCounterFeature")
.allowlist_item("v8__.*") .allowlist_item("v8__.*")
.allowlist_item("cppgc__.*") .allowlist_item("cppgc__.*")
.allowlist_item("RustObj")
.generate() .generate()
.expect("Unable to generate bindings"); .expect("Unable to generate bindings");

View File

@ -3856,24 +3856,19 @@ void v8__PropertyDescriptor__set_configurable(v8::PropertyDescriptor* self,
extern "C" { extern "C" {
class RustObj; void rusty_v8_RustObj_trace(const RustObj*, cppgc::Visitor*);
const char* rusty_v8_RustObj_get_name(const RustObj*);
void rusty_v8_RustObj_drop(RustObj*);
using RustTraceFn = void (*)(const RustObj* obj, cppgc::Visitor*); RustObj::~RustObj() { rusty_v8_RustObj_drop(this); }
using RustDestroyFn = void (*)(const RustObj* obj);
class RustObj final : public cppgc::GarbageCollected<RustObj> { void RustObj::Trace(cppgc::Visitor* visitor) const {
public: rusty_v8_RustObj_trace(this, visitor);
explicit RustObj(RustTraceFn trace, RustDestroyFn destroy) }
: trace_(trace), destroy_(destroy) {}
~RustObj() { destroy_(this); } const char* RustObj::GetHumanReadableName() const {
return rusty_v8_RustObj_get_name(this);
void Trace(cppgc::Visitor* visitor) const { trace_(this, visitor); } }
private:
RustTraceFn trace_;
RustDestroyFn destroy_;
};
RustObj* v8__Object__Unwrap(v8::Isolate* isolate, const v8::Object& wrapper, RustObj* v8__Object__Unwrap(v8::Isolate* isolate, const v8::Object& wrapper,
v8::CppHeapPointerTag tag) { v8::CppHeapPointerTag tag) {
@ -3930,12 +3925,9 @@ void cppgc__heap__collect_garbage_for_testing(
heap->CollectGarbageForTesting(stack_state); heap->CollectGarbageForTesting(stack_state);
} }
RustObj* cppgc__make_garbage_collectable(v8::CppHeap* heap, size_t size, RustObj* cppgc__make_garbage_collectable(v8::CppHeap* heap, size_t size) {
RustTraceFn trace,
RustDestroyFn destroy) {
return cppgc::MakeGarbageCollected<RustObj>(heap->GetAllocationHandle(), return cppgc::MakeGarbageCollected<RustObj>(heap->GetAllocationHandle(),
cppgc::AdditionalBytes(size), cppgc::AdditionalBytes(size));
trace, destroy);
} }
void cppgc__Visitor__Trace__Member(cppgc::Visitor* visitor, void cppgc__Visitor__Trace__Member(cppgc::Visitor* visitor,

View File

@ -11,8 +11,6 @@
* and made available in `crate::binding` in rust. * and made available in `crate::binding` in rust.
*/ */
class RustObj;
static size_t v8__ScriptOrigin_SIZE = sizeof(v8::ScriptOrigin); static size_t v8__ScriptOrigin_SIZE = sizeof(v8::ScriptOrigin);
static size_t cppgc__Member_SIZE = sizeof(cppgc::Member<RustObj>); static size_t cppgc__Member_SIZE = sizeof(cppgc::Member<RustObj>);

View File

@ -1,5 +1,6 @@
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license // Copyright 2019-2021 the Deno authors. All rights reserved. MIT license
use crate::binding::RustObj;
use crate::platform::Platform; use crate::platform::Platform;
use crate::support::int; use crate::support::int;
use crate::support::Opaque; use crate::support::Opaque;
@ -7,6 +8,8 @@ use crate::support::SharedRef;
use crate::support::UniqueRef; use crate::support::UniqueRef;
use crate::Data; use crate::Data;
use crate::TracedReference; use crate::TracedReference;
use std::ffi::c_char;
use std::ffi::CStr;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ptr::NonNull; use std::ptr::NonNull;
@ -24,8 +27,6 @@ extern "C" {
fn cppgc__make_garbage_collectable( fn cppgc__make_garbage_collectable(
heap: *mut Heap, heap: *mut Heap,
size: usize, size: usize,
trace: TraceFn,
destroy: DestroyFn,
) -> *mut RustObj; ) -> *mut RustObj;
fn cppgc__heap__enable_detached_garbage_collections_for_testing( fn cppgc__heap__enable_detached_garbage_collections_for_testing(
@ -83,14 +84,42 @@ extern "C" {
) -> *mut RustObj; ) -> *mut RustObj;
} }
type TraceFn = unsafe extern "C" fn(*const RustObj, *mut Visitor); unsafe fn get_rust_obj<'s>(obj: *const RustObj) -> &'s dyn GarbageCollected {
type DestroyFn = unsafe extern "C" fn(*const RustObj); &*std::mem::transmute::<[usize; 2], *mut dyn GarbageCollected>((*obj).data)
}
#[doc(hidden)] unsafe fn get_rust_obj_mut<'s>(
#[repr(C)] obj: *mut RustObj,
pub struct RustObj { ) -> &'s mut dyn GarbageCollected {
trace: TraceFn, &mut *std::mem::transmute::<[usize; 2], *mut dyn GarbageCollected>(
destroy: DestroyFn, (*obj).data,
)
}
#[no_mangle]
unsafe extern "C" fn rusty_v8_RustObj_trace(
obj: *const RustObj,
visitor: *mut Visitor,
) {
let r = get_rust_obj(obj);
r.trace(&*visitor);
}
#[no_mangle]
unsafe extern "C" fn rusty_v8_RustObj_get_name(
obj: *const RustObj,
) -> *const c_char {
let r = get_rust_obj(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_rust_obj_mut(obj);
std::ptr::drop_in_place(r);
} }
fn object_offset_for_rust_obj<T: GarbageCollected>() -> usize { fn object_offset_for_rust_obj<T: GarbageCollected>() -> usize {
@ -103,7 +132,10 @@ fn object_offset_for_rust_obj<T: GarbageCollected>() -> usize {
std::mem::offset_of!(Calc<T>, data) std::mem::offset_of!(Calc<T>, data)
} }
fn get_object_from_rust_obj<T: GarbageCollected>( /// # Safety
///
/// T must be the correct type for this specific RustObj
unsafe fn get_object_from_rust_obj<T: GarbageCollected>(
rust_obj: *const RustObj, rust_obj: *const RustObj,
) -> *mut T { ) -> *mut T {
unsafe { rust_obj.byte_add(object_offset_for_rust_obj::<T>()) as *mut T } unsafe { rust_obj.byte_add(object_offset_for_rust_obj::<T>()) as *mut T }
@ -276,7 +308,23 @@ impl Heap {
/// Base trait for managed objects. /// Base trait for managed objects.
pub trait GarbageCollected { pub trait GarbageCollected {
/// `trace` should call `Visitor::visit` for each
/// `Member`, `WeakMember`, or `TracedReference` in
/// by the managed object.
fn trace(&self, _visitor: &Visitor) {} 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. /// Constructs an instance of T, which is a garbage collected type.
@ -291,23 +339,10 @@ pub trait GarbageCollected {
/// ///
/// The caller must ensure that the returned pointer is always stored on /// 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. /// the stack, or is safely moved into one of the other cppgc pointer types.
pub unsafe fn make_garbage_collected<T: GarbageCollected>( pub unsafe fn make_garbage_collected<T: GarbageCollected + 'static>(
heap: &Heap, heap: &Heap,
obj: T, obj: T,
) -> Ptr<T> { ) -> Ptr<T> {
unsafe extern "C" fn trace<T: GarbageCollected>(
obj: *const RustObj,
visitor: *mut Visitor,
) {
let obj = unsafe { &*get_object_from_rust_obj::<T>(obj) };
obj.trace(unsafe { &*visitor });
}
unsafe extern "C" fn destroy<T: GarbageCollected>(obj: *const RustObj) {
let obj = get_object_from_rust_obj::<T>(obj);
std::ptr::drop_in_place(obj);
}
let additional_bytes = (object_offset_for_rust_obj::<T>() let additional_bytes = (object_offset_for_rust_obj::<T>()
- std::mem::size_of::<RustObj>()) - std::mem::size_of::<RustObj>())
+ std::mem::size_of::<T>(); + std::mem::size_of::<T>();
@ -316,13 +351,17 @@ pub unsafe fn make_garbage_collected<T: GarbageCollected>(
cppgc__make_garbage_collectable( cppgc__make_garbage_collectable(
heap as *const Heap as *mut _, heap as *const Heap as *mut _,
additional_bytes, additional_bytes,
trace::<T>,
destroy::<T>,
) )
}; };
unsafe { unsafe {
get_object_from_rust_obj::<T>(pointer).write(obj); let inner = get_object_from_rust_obj::<T>(pointer);
inner.write(obj);
let rust_obj = &mut *pointer;
rust_obj.data = std::mem::transmute::<*mut dyn GarbageCollected, [usize; 2]>(
&mut *inner as &mut dyn GarbageCollected as *mut dyn GarbageCollected,
);
} }
Ptr { Ptr {

View File

@ -1,7 +1,7 @@
use crate::binding::RustObj;
use crate::cppgc::GarbageCollected; use crate::cppgc::GarbageCollected;
use crate::cppgc::GetRustObj; use crate::cppgc::GetRustObj;
use crate::cppgc::Ptr; use crate::cppgc::Ptr;
use crate::cppgc::RustObj;
use crate::isolate::Isolate; use crate::isolate::Isolate;
use crate::support::int; use crate::support::int;
use crate::support::MapFnTo; use crate::support::MapFnTo;

View File

@ -9,6 +9,8 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "v8/include/cppgc/name-provider.h"
#include "v8/include/v8-cppgc.h"
#include "v8/include/v8.h" #include "v8/include/v8.h"
// Work around a bug in the V8 headers. // Work around a bug in the V8 headers.
@ -190,3 +192,12 @@ struct three_pointers_t {
V(BigInt64Array) V(BigInt64Array)
#endif // SUPPORT_H_ #endif // SUPPORT_H_
class RustObj final : public cppgc::GarbageCollected<RustObj>,
public cppgc::NameProvider {
public:
~RustObj();
void Trace(cppgc::Visitor* visitor) const;
const char* GetHumanReadableName() const final;
uintptr_t data[2];
};

View File

@ -44,6 +44,10 @@ fn cppgc_object_wrap() {
TRACE_COUNT.fetch_add(1, Ordering::SeqCst); TRACE_COUNT.fetch_add(1, Ordering::SeqCst);
visitor.trace(&self.value); visitor.trace(&self.value);
} }
fn get_name(&self) -> Option<&'static std::ffi::CStr> {
Some(c"Eyecatcher")
}
} }
impl Drop for Wrap { impl Drop for Wrap {
@ -134,6 +138,16 @@ fn cppgc_object_wrap() {
assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 0); assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 0);
{
let mut vec = Vec::<u8>::new();
scope.take_heap_snapshot(|chunk| {
vec.extend_from_slice(chunk);
true
});
let s = std::str::from_utf8(&vec).unwrap();
assert!(s.contains("Eyecatcher"));
}
scope.request_garbage_collection_for_testing( scope.request_garbage_collection_for_testing(
v8::GarbageCollectionType::Full, v8::GarbageCollectionType::Full,
); );