123 lines
3.3 KiB
Rust
123 lines
3.3 KiB
Rust
use crate::module::loader::{load_module, DefaultModuleLoader, ModuleLoader};
|
|
use crate::ContextRef;
|
|
use oden_js_sys as sys;
|
|
use std::cell::RefCell;
|
|
use std::ffi::CStr;
|
|
|
|
struct PrivateState {
|
|
refs: u64,
|
|
loader: Box<dyn ModuleLoader>,
|
|
}
|
|
|
|
impl PrivateState {
|
|
unsafe extern "C" fn module_loader(
|
|
ctx: *mut sys::JSContext,
|
|
path: *const i8,
|
|
opaque: *mut std::os::raw::c_void,
|
|
) -> *mut sys::JSModuleDef {
|
|
let path = match CStr::from_ptr(path).to_str() {
|
|
Ok(s) => s,
|
|
Err(_) => return std::ptr::null_mut(),
|
|
};
|
|
|
|
let state = opaque as *mut PrivateState;
|
|
let context = ContextRef::from_raw(ctx);
|
|
load_module(&context, path, &mut (*state).loader)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Runtime {
|
|
pub(crate) rt: *mut sys::JSRuntime,
|
|
}
|
|
|
|
impl Runtime {
|
|
pub fn new() -> Runtime {
|
|
Self::with_loader(DefaultModuleLoader::new())
|
|
}
|
|
|
|
pub fn with_loader<TLoader: ModuleLoader + 'static>(loader: TLoader) -> Runtime {
|
|
let state = Box::new(RefCell::new(PrivateState {
|
|
refs: 1,
|
|
loader: Box::new(loader),
|
|
}));
|
|
let rt = unsafe {
|
|
let rt = sys::JS_NewRuntime();
|
|
let state = Box::into_raw(state) as *mut _;
|
|
sys::JS_SetRuntimeOpaque(rt, state);
|
|
sys::JS_SetModuleLoaderFunc(rt, None, Some(PrivateState::module_loader), state);
|
|
rt
|
|
};
|
|
Runtime { rt }
|
|
}
|
|
|
|
pub(crate) fn from_raw(rt: *mut sys::JSRuntime) -> Self {
|
|
let mut state = unsafe {
|
|
let ptr = sys::JS_GetRuntimeOpaque(rt) as *const RefCell<PrivateState>;
|
|
ptr.as_ref()
|
|
.expect("We already know this runtime is one of ours!")
|
|
.borrow_mut()
|
|
};
|
|
state.refs += 1;
|
|
Runtime { rt }
|
|
}
|
|
|
|
pub fn set_memory_limit(&mut self, limit: usize) {
|
|
unsafe {
|
|
sys::JS_SetMemoryLimit(self.rt, limit);
|
|
}
|
|
}
|
|
|
|
pub fn set_gc_threshold(&mut self, threshold: usize) {
|
|
unsafe {
|
|
sys::JS_SetGCThreshold(self.rt, threshold);
|
|
}
|
|
}
|
|
|
|
/// Pass in 0 to disable the maximum size check.
|
|
pub fn set_max_stack_size(&mut self, max_stack: usize) {
|
|
unsafe {
|
|
sys::JS_SetMaxStackSize(self.rt, max_stack);
|
|
}
|
|
}
|
|
|
|
pub fn run_gc(&mut self) {
|
|
unsafe {
|
|
sys::JS_RunGC(self.rt);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Clone for Runtime {
|
|
fn clone(&self) -> Self {
|
|
Runtime::from_raw(self.rt)
|
|
}
|
|
}
|
|
|
|
impl Drop for Runtime {
|
|
fn drop(&mut self) {
|
|
let should_free = {
|
|
let mut state = unsafe {
|
|
let ptr = sys::JS_GetRuntimeOpaque(self.rt) as *const RefCell<PrivateState>;
|
|
ptr.as_ref()
|
|
.expect("We already know this runtime is one of ours!")
|
|
.borrow_mut()
|
|
};
|
|
state.refs -= 1;
|
|
state.refs == 0
|
|
};
|
|
|
|
if should_free {
|
|
unsafe {
|
|
let opaque = sys::JS_GetRuntimeOpaque(self.rt);
|
|
sys::JS_RunGC(self.rt);
|
|
sys::JS_FreeRuntime(self.rt);
|
|
|
|
if !opaque.is_null() {
|
|
// Just let the system drop it here.
|
|
let _ = Box::from_raw(opaque as *mut RefCell<PrivateState>);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|