rw_deno_core/
cppgc.rs

1// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2
3use std::any::TypeId;
4
5struct CppGcObject<T> {
6  tag: TypeId,
7  member: T,
8}
9
10impl<T> v8::cppgc::GarbageCollected for CppGcObject<T> {
11  fn trace(&self, _: &v8::cppgc::Visitor) {}
12}
13
14pub(crate) const DEFAULT_CPP_GC_EMBEDDER_ID: u16 = 0xde90;
15
16const EMBEDDER_ID_OFFSET: i32 = 0;
17const SLOT_OFFSET: i32 = 1;
18const FIELD_COUNT: usize = 2;
19
20pub fn make_cppgc_object<'a, T: 'static>(
21  scope: &mut v8::HandleScope<'a>,
22  t: T,
23) -> v8::Local<'a, v8::Object> {
24  let templ = v8::ObjectTemplate::new(scope);
25  templ.set_internal_field_count(FIELD_COUNT);
26
27  let obj = templ.new_instance(scope).unwrap();
28  let member = v8::cppgc::make_garbage_collected(
29    scope.get_cpp_heap().unwrap(),
30    Box::new(CppGcObject {
31      tag: TypeId::of::<T>(),
32      member: t,
33    }),
34  );
35
36  obj.set_aligned_pointer_in_internal_field(
37    EMBEDDER_ID_OFFSET,
38    &DEFAULT_CPP_GC_EMBEDDER_ID as *const u16 as _,
39  );
40  obj.set_aligned_pointer_in_internal_field(SLOT_OFFSET, member.handle as _);
41  obj
42}
43
44pub fn try_unwrap_cppgc_object<'sc, T: 'static>(
45  val: v8::Local<v8::Value>,
46) -> Option<&'sc T> {
47  let Ok(obj): Result<v8::Local<v8::Object>, _> = val.try_into() else {
48    return None;
49  };
50
51  if obj.internal_field_count() != FIELD_COUNT {
52    return None;
53  }
54
55  // SAFETY: This code works under the assumption that
56  // there is no other way to obtain an object with
57  // internal field count of 2.
58  //
59  // The object can only be created by `make_cppgc_object`.
60  let member = unsafe {
61    let ptr = obj.get_aligned_pointer_from_internal_field(SLOT_OFFSET);
62    let obj = &*(ptr as *const v8::cppgc::InnerMember);
63    obj.get::<CppGcObject<T>>()
64  };
65
66  if member.tag != TypeId::of::<T>() {
67    return None;
68  }
69
70  Some(&member.member)
71}