Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 6 additions & 38 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ napi-build = { version = "2.1.4" }
napi-derive = { version = "3.0.0-alpha.22" }

# Serialize and Deserialize
inventory = { version = "=0.1" }
inventory = { version = "0.3.17" }
rkyv = { version = "=0.8.8" }

# Must be pinned with the same swc versions
Expand Down
1 change: 1 addition & 0 deletions crates/rspack_cacheable/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ serde_json = { workspace = true }
smol_str = { workspace = true }
swc_core = { workspace = true, features = ["ecma_ast"] }
ustr = { workspace = true }
xxhash-rust = { workspace = true, features = ["const_xxh64"] }
36 changes: 20 additions & 16 deletions crates/rspack_cacheable/src/dyn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ use rkyv::{
};

pub mod validation;
mod vtable_ptr;

pub use vtable_ptr::VTablePtr;

use crate::{DeserializeError, Deserializer, SerializeError, Serializer};

/// A trait object that can be archived.
Expand Down Expand Up @@ -140,35 +144,35 @@ impl<T: ?Sized> ArchivedDynMetadata<T> {
/// Returns the pointer metadata for the trait object this metadata refers to.
pub fn lookup_metadata(&self) -> DynMetadata<T> {
unsafe {
std::mem::transmute(
*DYN_REGISTRY
.get(&self.dyn_id.to_native())
.expect("attempted to get vtable for an unregistered impl"),
)
DYN_REGISTRY
.get(&self.dyn_id.to_native())
.expect("attempted to get vtable for an unregistered impl")
.cast()
}
}
}

pub struct DynEntry {
dyn_id: u64,
vtable: usize,
vtable: VTablePtr,
}

impl DynEntry {
pub fn new(dyn_id: u64, vtable: usize) -> Self {
pub const fn new(dyn_id: u64, vtable: VTablePtr) -> Self {
Self { dyn_id, vtable }
}
}

inventory::collect!(DynEntry);

static DYN_REGISTRY: std::sync::LazyLock<HashMap<u64, usize>> = std::sync::LazyLock::new(|| {
let mut result = HashMap::default();
for entry in inventory::iter::<DynEntry> {
let old_value = result.insert(entry.dyn_id, entry.vtable);
if old_value.is_some() {
panic!("cacheable_dyn init global REGISTRY error, duplicate implementation.")
static DYN_REGISTRY: std::sync::LazyLock<HashMap<u64, VTablePtr>> =
std::sync::LazyLock::new(|| {
let mut result = HashMap::default();
for entry in inventory::iter::<DynEntry> {
let old_value = result.insert(entry.dyn_id, entry.vtable);
if old_value.is_some() {
panic!("cacheable_dyn init global REGISTRY error, duplicate implementation.")
}
}
}
result
});
result
});
7 changes: 4 additions & 3 deletions crates/rspack_cacheable/src/dyn/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::HashMap;

use rkyv::bytecheck::CheckBytes;

use super::VTablePtr;
use crate::{DeserializeError, Validator};

type CheckBytesDyn = unsafe fn(*const u8, &mut Validator<'_>) -> Result<(), DeserializeError>;
Expand All @@ -20,13 +21,13 @@ where
}

pub struct CheckBytesEntry {
vtable: usize,
vtable: VTablePtr,
check_bytes_dyn: CheckBytesDyn,
}

impl CheckBytesEntry {
#[doc(hidden)]
pub fn new(vtable: usize, check_bytes_dyn: CheckBytesDyn) -> Self {
pub const fn new(vtable: VTablePtr, check_bytes_dyn: CheckBytesDyn) -> Self {
Self {
vtable,
check_bytes_dyn,
Expand All @@ -36,7 +37,7 @@ impl CheckBytesEntry {

inventory::collect!(CheckBytesEntry);

pub static CHECK_BYTES_REGISTRY: std::sync::LazyLock<HashMap<usize, CheckBytesDyn>> =
pub static CHECK_BYTES_REGISTRY: std::sync::LazyLock<HashMap<VTablePtr, CheckBytesDyn>> =
std::sync::LazyLock::new(|| {
let mut result = HashMap::default();
for entry in inventory::iter::<CheckBytesEntry> {
Expand Down
21 changes: 21 additions & 0 deletions crates/rspack_cacheable/src/dyn/vtable_ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use rkyv::ptr_meta::DynMetadata;

/// A untyped wrapper for vtable
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub struct VTablePtr(DynMetadata<()>);

impl VTablePtr {
pub const fn new<T: ?Sized>(vtable: DynMetadata<T>) -> Self {
// Creating VTablePtr is safe while using it is unsafe, just like raw pointers in rust.
Self(unsafe { core::mem::transmute::<DynMetadata<T>, DynMetadata<()>>(vtable) })
}

/// # Safety
/// The casting target `T` must be consistent with the `T` in VTablePtr::new<T>
/// Currently it is implemented by store VTablePtr as values in HashMap to associate the types with __DYN_ID
pub const unsafe fn cast<T: ?Sized>(self) -> DynMetadata<T> {
core::mem::transmute(self.0)
}
}
unsafe impl Send for VTablePtr {}
unsafe impl Sync for VTablePtr {}
1 change: 1 addition & 0 deletions crates/rspack_cacheable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ pub mod __private {

pub use deserialize::{from_bytes, DeserializeError, Deserializer, Validator};
pub use serialize::{to_bytes, SerializeError, Serializer};
pub use xxhash_rust;
1 change: 1 addition & 0 deletions crates/rspack_cacheable_test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ rustc-hash = { workspace = true }
serde_json = { workspace = true }
swc_core = { workspace = true, features = ["ecma_ast"] }
ustr = { workspace = true }
xxhash-rust = { workspace = true, features = ["const_xxh64"] }
50 changes: 18 additions & 32 deletions crates/rspack_cacheable_test/tests/macro/manual_cacheable_dyn.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rspack_cacheable::{cacheable, from_bytes, to_bytes};
use rspack_cacheable::{cacheable, from_bytes, r#dyn::VTablePtr, to_bytes};

#[test]
#[cfg_attr(miri, ignore)]
Expand Down Expand Up @@ -99,7 +99,7 @@ fn test_manual_cacheable_dyn_macro() {
value: *const Self,
context: &mut Validator,
) -> Result<(), DeserializeError> {
let vtable: usize = std::mem::transmute(ptr_meta::metadata(value));
let vtable = VTablePtr::new(ptr_meta::metadata(value));
if let Some(check_bytes_dyn) = CHECK_BYTES_REGISTRY.get(&vtable) {
check_bytes_dyn(value.cast(), context)?;
Ok(())
Expand All @@ -115,13 +115,8 @@ fn test_manual_cacheable_dyn_macro() {
color: String,
}

static __DYN_ID_DOG_ANIMAL: std::sync::LazyLock<u64> = std::sync::LazyLock::new(|| {
use std::hash::{DefaultHasher, Hash, Hasher};
let mut hasher = DefaultHasher::new();
module_path!().hash(&mut hasher);
line!().hash(&mut hasher);
hasher.finish()
});
const __DYN_ID_DOG_ANIMAL: u64 =
xxhash_rust::const_xxh64::xxh64(concat!(module_path!(), ":", line!()).as_bytes(), 0);

impl Animal for Dog {
fn color(&self) -> &str {
Expand All @@ -132,7 +127,7 @@ fn test_manual_cacheable_dyn_macro() {
}

fn __dyn_id(&self) -> u64 {
*__DYN_ID_DOG_ANIMAL
__DYN_ID_DOG_ANIMAL
}
}

Expand All @@ -149,14 +144,12 @@ fn test_manual_cacheable_dyn_macro() {
DeserializeError, Deserializer,
};

fn get_vtable() -> usize {
unsafe {
core::mem::transmute(ptr_meta::metadata(
core::ptr::null::<Archived<Dog>>() as *const <dyn Animal as ArchiveUnsized>::Archived
))
}
const fn get_vtable() -> VTablePtr {
VTablePtr::new(ptr_meta::metadata(
core::ptr::null::<Archived<Dog>>() as *const <dyn Animal as ArchiveUnsized>::Archived
))
}
inventory::submit! { DynEntry::new(*__DYN_ID_DOG_ANIMAL, get_vtable()) }
inventory::submit! { DynEntry::new(__DYN_ID_DOG_ANIMAL, get_vtable()) }
inventory::submit! { CheckBytesEntry::new(get_vtable(), default_check_bytes_dyn::<Archived<Dog>>) }

impl DeserializeDyn<dyn Animal> for ArchivedDog
Expand Down Expand Up @@ -184,13 +177,8 @@ fn test_manual_cacheable_dyn_macro() {
color: String,
}

static __DYN_ID_CAT_ANIMAL: std::sync::LazyLock<u64> = std::sync::LazyLock::new(|| {
use std::hash::{DefaultHasher, Hash, Hasher};
let mut hasher = DefaultHasher::new();
module_path!().hash(&mut hasher);
line!().hash(&mut hasher);
hasher.finish()
});
const __DYN_ID_CAT_ANIMAL: u64 =
xxhash_rust::const_xxh64::xxh64(concat!(module_path!(), ":", line!()).as_bytes(), 0);

impl Animal for Cat {
fn color(&self) -> &str {
Expand All @@ -201,7 +189,7 @@ fn test_manual_cacheable_dyn_macro() {
}

fn __dyn_id(&self) -> u64 {
*__DYN_ID_CAT_ANIMAL
__DYN_ID_CAT_ANIMAL
}
}

Expand All @@ -218,14 +206,12 @@ fn test_manual_cacheable_dyn_macro() {
DeserializeError, Deserializer,
};

fn get_vtable() -> usize {
unsafe {
core::mem::transmute(ptr_meta::metadata(
core::ptr::null::<Archived<Cat>>() as *const <dyn Animal as ArchiveUnsized>::Archived
))
}
const fn get_vtable() -> VTablePtr {
VTablePtr::new(ptr_meta::metadata(
core::ptr::null::<Archived<Cat>>() as *const <dyn Animal as ArchiveUnsized>::Archived
))
}
inventory::submit! { DynEntry::new(*__DYN_ID_CAT_ANIMAL, get_vtable()) }
inventory::submit! { DynEntry::new(__DYN_ID_CAT_ANIMAL, get_vtable()) }
inventory::submit! { CheckBytesEntry::new(get_vtable(), default_check_bytes_dyn::<Archived<Cat>>) }

impl DeserializeDyn<dyn Animal> for ArchivedCat
Expand Down
Loading
Loading