Skip to main content

rquickjs_core/
runtime.rs

1//! QuickJS runtime related types.
2
3mod base;
4mod exotic;
5pub(crate) mod opaque;
6pub(crate) mod raw;
7mod userdata;
8
9#[cfg(feature = "jit-abi")]
10mod jit;
11
12#[doc(hidden)]
13#[cfg(feature = "jit-test-support")]
14pub mod test_support;
15
16#[cfg(feature = "futures")]
17mod r#async;
18#[cfg(feature = "futures")]
19pub(crate) mod schedular;
20#[cfg(feature = "futures")]
21mod spawner;
22#[cfg(feature = "futures")]
23pub use spawner::DriveFuture;
24
25use alloc::boxed::Box;
26pub use base::{Runtime, WeakRuntime};
27#[cfg(feature = "jit-abi")]
28#[cfg_attr(feature = "doc-cfg", doc(cfg(feature = "jit-abi")))]
29pub use jit::{
30    JitBackend, JitBackendAttachError, JitFunctionRegistry, JitFunctionRegistryError,
31    RuntimeJitGuard,
32};
33pub use userdata::{UserDataError, UserDataGuard};
34
35#[cfg(feature = "futures")]
36pub(crate) use r#async::InnerRuntime;
37#[cfg(feature = "futures")]
38pub use r#async::{AsyncRuntime, AsyncWeakRuntime};
39
40use crate::value::promise::PromiseHookType;
41use crate::{Ctx, Value};
42
43/// The type of the promise hook.
44#[cfg(not(feature = "parallel"))]
45pub type PromiseHook =
46    Box<dyn for<'a> Fn(Ctx<'a>, PromiseHookType, Value<'a>, Value<'a>) + 'static>;
47/// The type of the promise hook.
48#[cfg(feature = "parallel")]
49pub type PromiseHook =
50    Box<dyn for<'a> Fn(Ctx<'a>, PromiseHookType, Value<'a>, Value<'a>) + Send + 'static>;
51
52/// The type of the promise rejection tracker.
53#[cfg(not(feature = "parallel"))]
54pub type RejectionTracker = Box<dyn for<'a> Fn(Ctx<'a>, Value<'a>, Value<'a>, bool) + 'static>;
55/// The type of the promise rejection tracker.
56#[cfg(feature = "parallel")]
57pub type RejectionTracker =
58    Box<dyn for<'a> Fn(Ctx<'a>, Value<'a>, Value<'a>, bool) + Send + 'static>;
59
60/// The type of the interrupt handler.
61#[cfg(not(feature = "parallel"))]
62pub type InterruptHandler = Box<dyn FnMut() -> bool + 'static>;
63/// The type of the interrupt handler.
64#[cfg(feature = "parallel")]
65pub type InterruptHandler = Box<dyn FnMut() -> bool + Send + 'static>;
66
67/// A struct with information about the runtimes memory usage.
68pub type MemoryUsage = crate::qjs::JSMemoryUsage;
69
70#[cfg(all(test, feature = "jit-abi"))]
71mod test {
72    use alloc::sync::Arc;
73    use core::{
74        mem,
75        sync::atomic::{AtomicBool, Ordering},
76    };
77
78    use super::{JitBackend, Runtime};
79    use crate::qjs;
80
81    struct DetachProbe(Arc<AtomicBool>);
82
83    unsafe impl JitBackend for DetachProbe {
84        fn runtime_detach(&mut self) {
85            self.0.store(true, Ordering::SeqCst);
86        }
87    }
88
89    #[test]
90    fn guard_detaches_backend_while_runtime_is_alive() {
91        let runtime = Runtime::new().unwrap();
92        let detached = Arc::new(AtomicBool::new(false));
93        let guard = runtime
94            .attach_jit_backend(DetachProbe(Arc::clone(&detached)))
95            .unwrap();
96        let clone = runtime.clone();
97
98        drop(runtime);
99        drop(guard);
100        assert!(detached.load(Ordering::SeqCst));
101        clone.run_gc();
102    }
103
104    #[test]
105    fn engine_rejects_a_mismatched_vtable_size() {
106        let runtime = Runtime::new().unwrap();
107        let raw = runtime.inner.lock();
108        let mut vtable = unsafe { mem::zeroed::<qjs::JSJitBackendVTable>() };
109        vtable.struct_size = mem::size_of::<qjs::JSJitBackendVTable>() as u32 - 1;
110        let status =
111            unsafe { qjs::JS_SetJitBackend(raw.rt.as_ptr(), &vtable, core::ptr::null_mut()) };
112        assert_eq!(status, qjs::JS_JIT_BACKEND_INVALID_VTABLE);
113    }
114
115    #[test]
116    fn engine_detach_is_idempotent() {
117        let runtime = Runtime::new().unwrap();
118        let raw = runtime.inner.lock();
119        for _ in 0..2 {
120            let status = unsafe {
121                qjs::JS_SetJitBackend(raw.rt.as_ptr(), core::ptr::null(), core::ptr::null_mut())
122            };
123            assert_eq!(status, qjs::JS_JIT_BACKEND_OK);
124        }
125    }
126}