mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-21 05:43:13 -05:00
feat: cppgc NameProvider (#1528)
This commit is contained in:
parent
8a5f484c71
commit
b2ef529146
7 changed files with 105 additions and 50 deletions
1
build.rs
1
build.rs
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>);
|
||||||
|
|
93
src/cppgc.rs
93
src/cppgc.rs
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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];
|
||||||
|
};
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue