feat: 实现 vm 内存模型、引用计数与持久化堆
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
#![doc = "OxideJS - Register-based VM with epoch arena memory"]
|
#![doc = "OxideJS - Register-based VM with epoch arena memory"]
|
||||||
|
|
||||||
|
pub mod mem;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub use value::JsValue;
|
pub use value::JsValue;
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Reference-counted persistent pointer.
|
||||||
|
///
|
||||||
|
/// Wraps `Arc<T>` for cross-epoch object storage. `Clone` increments the
|
||||||
|
/// reference count; `Drop` decrements it. Objects wrapped in `P<T>` survive
|
||||||
|
/// `Epoch::reset()` — they live on the global heap.
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct P<T>(Arc<T>);
|
||||||
|
|
||||||
|
impl<T> P<T> {
|
||||||
|
pub fn new(value: T) -> Self {
|
||||||
|
Self(Arc::new(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for P<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(Arc::clone(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for P<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug> fmt::Debug for P<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "P({:?})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Display> fmt::Display for P<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Persistent heap for cross-epoch object storage.
|
||||||
|
///
|
||||||
|
/// Phase 3 provides a minimal API: `promote(value)` moves `value` to the
|
||||||
|
/// global heap under `Arc` and returns `P<T>`. Phase 7 (OxideKernel) expands
|
||||||
|
/// with typed storage for shapes, code, IC templates, and strings.
|
||||||
|
pub struct PersistentHeap;
|
||||||
|
|
||||||
|
impl PersistentHeap {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move a value to the persistent heap and return a reference-counted pointer.
|
||||||
|
/// The returned `P<T>` survives epoch resets — it's stored on the global heap
|
||||||
|
/// under `Arc`.
|
||||||
|
pub fn promote<T>(&self, value: T) -> P<T> {
|
||||||
|
P::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PersistentHeap {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///
|
||||||
|
/// Wraps `bumpalo::Bump` with an epoch ID counter for dangling pointer detection.
|
||||||
|
/// All Agent-call objects are allocated here; `reset()` clears them in O(1)
|
||||||
|
/// at the end of each call.
|
||||||
|
pub struct Epoch {
|
||||||
|
bump: bumpalo::Bump,
|
||||||
|
epoch_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Epoch {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
bump: bumpalo::Bump::new(),
|
||||||
|
epoch_id: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bump-allocate a value and return a raw pointer to it.
|
||||||
|
/// The pointer is valid until `reset()` is called.
|
||||||
|
pub fn alloc<T>(&self, value: T) -> *mut T {
|
||||||
|
self.bump.alloc(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bump-allocate a value using a closure for initialization.
|
||||||
|
/// Better for compiler optimization — construct directly on arena.
|
||||||
|
pub fn alloc_with<T, F>(&self, f: F) -> *mut T
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T,
|
||||||
|
{
|
||||||
|
self.bump.alloc_with(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// O(1) mass deallocation. All previous allocations become invalid.
|
||||||
|
/// Increments epoch ID to invalidate stale pointers (debug_assert guard).
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.bump.reset();
|
||||||
|
self.epoch_id += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Current epoch ID. Arena-allocated objects store this value;
|
||||||
|
/// dereference checks they match the current ID (debug_assert only).
|
||||||
|
pub fn current_id(&self) -> u64 {
|
||||||
|
self.epoch_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Epoch {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user