[oden] The big lifetime removal

It turns out that rust can't really reason about the relationship
between the runtime lifetime and the context lifetime in a way that is
actually usable. This removes the lifetime stuff in favor of reference
counting the runtime itself, via a block that we embed in the
pointer. This, I think, it the least worst option here.
This commit is contained in:
John Doty 2023-06-19 08:28:26 -07:00
parent 898b1fe129
commit 9f808cea31
10 changed files with 269 additions and 312 deletions

View file

@ -1,4 +1,9 @@
use oden_js_sys as sys;
use std::cell::RefCell;
struct PrivateState {
refs: u64,
}
#[derive(Debug)]
pub struct Runtime {
@ -7,7 +12,23 @@ pub struct Runtime {
impl Runtime {
pub fn new() -> Runtime {
let rt = unsafe { sys::JS_NewRuntime() };
let state = Box::new(RefCell::new(PrivateState { refs: 1 }));
let rt = unsafe {
let rt = sys::JS_NewRuntime();
sys::JS_SetRuntimeOpaque(rt, Box::into_raw(state) as *mut _);
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 }
}
@ -37,11 +58,36 @@ impl Runtime {
}
}
impl Clone for Runtime {
fn clone(&self) -> Self {
Runtime::from_raw(self.rt)
}
}
impl Drop for Runtime {
fn drop(&mut self) {
unsafe {
sys::JS_RunGC(self.rt);
sys::JS_FreeRuntime(self.rt);
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>);
}
}
}
}
}