diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 01fa053f..842c1ceb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -381,7 +381,9 @@ jobs: overwrite: true - name: Build if: ${{ !matrix.no-build }} - run: cargo build ${{ matrix.optimization && '--release' || '' }} --target ${{ matrix.target }} --no-default-features --features ${{ matrix.features }} + run: | + cargo clean + cargo build ${{ matrix.optimization && '--release' || '' }} --target ${{ matrix.target }} --no-default-features --features ${{ matrix.features }} - name: Test if: ${{ !matrix.no-build && !matrix.no-test }} timeout-minutes: 12 diff --git a/core/src/class/id.rs b/core/src/class/id.rs index 52013919..e0837481 100644 --- a/core/src/class/id.rs +++ b/core/src/class/id.rs @@ -1,13 +1,10 @@ use rquickjs_sys::JSRuntime; -use crate::qjs; -use std::{ - collections::HashMap, - sync::{ - atomic::{AtomicUsize, Ordering}, - OnceLock, RwLock, - }, +use crate::{ + qjs, + runtime::opaque::{ClassIdKey, Opaque}, }; +use std::sync::atomic::{AtomicUsize, Ordering}; /// The type of identifier of class #[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "classes")))] @@ -15,14 +12,7 @@ pub struct ClassId { type_id: AtomicUsize, } -#[derive(Eq, Hash, PartialEq)] -struct ClassIdKey(*mut JSRuntime, usize); - -unsafe impl Sync for ClassIdKey {} -unsafe impl Send for ClassIdKey {} - static CLASS_ID_COUNTER: AtomicUsize = AtomicUsize::new(1); -static CLASS_ID_MAP: OnceLock>> = OnceLock::new(); impl ClassId { /// Create a new class id. @@ -39,18 +29,15 @@ impl ClassId { pub fn get(&self, rt: *mut JSRuntime) -> qjs::JSClassID { let type_id = self.init_type_id(); let key = ClassIdKey(rt, type_id); - let class_id_lock = CLASS_ID_MAP.get_or_init(|| RwLock::new(HashMap::new())); - if let Some(class_id) = class_id_lock.read().unwrap().get(&key) { - return *class_id; - } - let mut read_lock = class_id_lock.write().unwrap(); - let mut id = 0; - unsafe { qjs::JS_NewClassID(rt, &mut id) }; + let opaque = unsafe { &(*qjs::JS_GetRuntimeOpaque(rt).cast::()) }; - read_lock.insert(key, id); - - id + let id = opaque.get_class_id_map().entry(key).or_insert_with(|| { + let mut id = 0; + unsafe { qjs::JS_NewClassID(rt, &mut id) }; + id + }); + *id } /// Initialize the class ID. diff --git a/core/src/runtime/opaque.rs b/core/src/runtime/opaque.rs index 00c0f982..1fa4d9c5 100644 --- a/core/src/runtime/opaque.rs +++ b/core/src/runtime/opaque.rs @@ -1,3 +1,7 @@ +use rquickjs_sys::JSRuntime; + +use crate::qjs; + use super::{ userdata::{UserDataGuard, UserDataMap}, InterruptHandler, UserData, UserDataError, @@ -5,6 +9,7 @@ use super::{ use std::{ any::Any, cell::{Cell, UnsafeCell}, + collections::HashMap, marker::PhantomData, }; @@ -17,6 +22,9 @@ use std::{ task::{Context, Waker}, }; +#[derive(Eq, Hash, PartialEq)] +pub struct ClassIdKey(pub *mut JSRuntime, pub usize); + /// Opaque book keeping data for Rust. pub(crate) struct Opaque<'js> { /// Used to carry a panic if a callback triggered one. @@ -25,6 +33,8 @@ pub(crate) struct Opaque<'js> { /// The user provided interrupt handler, if any. interrupt_handler: UnsafeCell>, + class_id_map: UnsafeCell>, + userdata: UserDataMap, #[cfg(feature = "futures")] @@ -38,6 +48,7 @@ impl<'js> Opaque<'js> { Opaque { panic: Cell::new(None), interrupt_handler: UnsafeCell::new(None), + class_id_map: UnsafeCell::new(HashMap::new()), userdata: UserDataMap::default(), #[cfg(feature = "futures")] spawner: None, @@ -50,6 +61,7 @@ impl<'js> Opaque<'js> { Opaque { panic: Cell::new(None), interrupt_handler: UnsafeCell::new(None), + class_id_map: UnsafeCell::new(HashMap::new()), userdata: UserDataMap::default(), #[cfg(feature = "futures")] spawner: Some(UnsafeCell::new(Spawner::new())), @@ -120,4 +132,8 @@ impl<'js> Opaque<'js> { pub fn take_panic(&self) -> Option> { self.panic.take() } + + pub(crate) fn get_class_id_map(&self) -> &mut HashMap { + unsafe { &mut *self.class_id_map.get() } + } } diff --git a/core/src/runtime/raw.rs b/core/src/runtime/raw.rs index 20af36b2..5ddb1422 100644 --- a/core/src/runtime/raw.rs +++ b/core/src/runtime/raw.rs @@ -121,8 +121,8 @@ impl Drop for RawRuntime { unsafe { let ptr = qjs::JS_GetRuntimeOpaque(self.rt.as_ptr()); let opaque: Box = Box::from_raw(ptr as *mut _); + qjs::JS_FreeRuntime(self.rt.as_ptr()); mem::drop(opaque); - qjs::JS_FreeRuntime(self.rt.as_ptr()) } } }