feat: 实现全局属性布局共享缓存池

This commit is contained in:
2026-06-05 21:35:51 +08:00
parent c7b8b22cf7
commit 1d9e20fe31
2 changed files with 256 additions and 0 deletions
+1
View File
@@ -1,3 +1,4 @@
#![doc = "OxideJS - Shared kernel (CodeForge, ShapeForge, IcForge, StringForge, BuiltinWorld)"] #![doc = "OxideJS - Shared kernel (CodeForge, ShapeForge, IcForge, StringForge, BuiltinWorld)"]
pub mod shape_forge;
pub mod string_forge; pub mod string_forge;
+255
View File
@@ -0,0 +1,255 @@
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, RwLock};
use dashmap::DashMap;
pub type ShapeId = u32;
pub type StringIndex = u32;
pub const EMPTY_SHAPE_ID: ShapeId = 1;
const EMPTY_SENTINEL: StringIndex = u32::MAX;
#[derive(Debug, Clone)]
pub struct Shape {
pub id: ShapeId,
pub property_name: StringIndex,
pub property_offset: u8,
pub parent: Option<ShapeId>,
}
pub struct ShapeForge {
shapes: RwLock<Vec<Option<Arc<Shape>>>>,
transitions: DashMap<u64, ShapeId>,
next_id: AtomicU32,
}
impl ShapeForge {
pub fn new() -> Self {
let forge = Self {
shapes: RwLock::new(Vec::with_capacity(256)),
transitions: DashMap::with_capacity(256),
next_id: AtomicU32::new(2),
};
{
let mut shapes = forge.shapes.write().unwrap();
let empty = Arc::new(Shape {
id: EMPTY_SHAPE_ID,
property_name: EMPTY_SENTINEL,
property_offset: 0,
parent: None,
});
debug_assert_eq!(shapes.len(), 0);
shapes.push(Some(empty));
}
forge
}
pub fn pack_key(parent_id: ShapeId, prop_name: StringIndex) -> u64 {
((parent_id as u64) << 32) | (prop_name as u64)
}
fn compute_offset_inner(shape_id: ShapeId, shapes: &[Option<Arc<Shape>>]) -> u8 {
let mut count = 0u8;
let mut cursor = Some(shape_id);
while let Some(id) = cursor {
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
Some(s) => {
if s.property_name != EMPTY_SENTINEL {
count += 1;
}
cursor = s.parent;
}
None => break,
}
}
count.min(31)
}
pub fn make_shape(&self, parent_id: ShapeId, prop_name: StringIndex) -> ShapeId {
let key = Self::pack_key(parent_id, prop_name);
if let Some(entry) = self.transitions.get(&key) {
return *entry;
}
let shapes_read = self.shapes.read().unwrap();
let prop_offset = Self::compute_offset_inner(parent_id, &shapes_read);
drop(shapes_read);
let new_id = self.next_id.fetch_add(1, Ordering::Relaxed);
let shape = Arc::new(Shape {
id: new_id,
property_name: prop_name,
property_offset: prop_offset,
parent: Some(parent_id),
});
{
let mut shapes = self.shapes.write().unwrap();
while shapes.len() < new_id as usize {
shapes.push(None);
}
shapes[(new_id - 1) as usize] = Some(shape);
}
*self.transitions.entry(key).or_insert(new_id).value()
}
pub fn get_shape(&self, id: ShapeId) -> Option<Arc<Shape>> {
let shapes = self.shapes.read().unwrap();
shapes.get((id - 1) as usize).and_then(|s| s.clone())
}
pub fn lookup_offset(&self, shape_id: ShapeId, prop_name: StringIndex) -> Option<u8> {
let shapes = self.shapes.read().unwrap();
let mut cursor = Some(shape_id);
while let Some(id) = cursor {
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
Some(s) => {
if s.property_name == prop_name && s.property_name != EMPTY_SENTINEL {
return Some(s.property_offset);
}
cursor = s.parent;
}
None => return None,
}
}
None
}
pub fn shape_prop_count(&self, shape_id: ShapeId) -> u8 {
let shapes = self.shapes.read().unwrap();
let mut count = 0u8;
let mut cursor = Some(shape_id);
while let Some(id) = cursor {
match shapes.get((id - 1) as usize).and_then(|s| s.clone()) {
Some(s) => {
if s.property_name != EMPTY_SENTINEL {
count += 1;
}
cursor = s.parent;
}
None => break,
}
}
count
}
}
impl Default for ShapeForge {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Barrier;
#[test]
fn empty_shape_exists() {
let forge = ShapeForge::new();
let s = forge.get_shape(EMPTY_SHAPE_ID);
assert!(s.is_some());
let s = s.unwrap();
assert_eq!(s.id, EMPTY_SHAPE_ID);
assert!(s.parent.is_none());
}
#[test]
fn make_shape_creates_new_id() {
let forge = ShapeForge::new();
let key: StringIndex = 1_000_000;
let s1 = forge.make_shape(EMPTY_SHAPE_ID, key);
assert!(s1 > EMPTY_SHAPE_ID);
let shape = forge.get_shape(s1).unwrap();
assert_eq!(shape.property_name, key);
assert_eq!(shape.parent, Some(EMPTY_SHAPE_ID));
}
#[test]
fn hash_cons_returns_same_id() {
let forge = ShapeForge::new();
let key: StringIndex = 1_000_001;
let a = forge.make_shape(EMPTY_SHAPE_ID, key);
let b = forge.make_shape(EMPTY_SHAPE_ID, key);
assert_eq!(a, b);
}
#[test]
fn different_props_different_ids() {
let forge = ShapeForge::new();
let a = forge.make_shape(EMPTY_SHAPE_ID, 1_000_002);
let b = forge.make_shape(EMPTY_SHAPE_ID, 1_000_003);
assert_ne!(a, b);
}
#[test]
fn chain_of_three() {
let forge = ShapeForge::new();
let s1 = forge.make_shape(EMPTY_SHAPE_ID, 1_000_010);
let s2 = forge.make_shape(s1, 1_000_020);
let s3 = forge.make_shape(s2, 1_000_030);
assert_eq!(forge.shape_prop_count(s3), 3);
assert_eq!(forge.lookup_offset(s3, 1_000_030), Some(2));
assert_eq!(forge.lookup_offset(s3, 1_000_020), Some(1));
assert_eq!(forge.lookup_offset(s3, 1_000_010), Some(0));
assert_eq!(forge.lookup_offset(s3, 99), None);
}
#[test]
fn two_branches_share_ancestor() {
let forge = ShapeForge::new();
let base = forge.make_shape(EMPTY_SHAPE_ID, 1_000_040);
let branch_a = forge.make_shape(base, 1_000_050);
let branch_b = forge.make_shape(base, 1_000_060);
assert_ne!(branch_a, branch_b);
let a_shape = forge.get_shape(branch_a).unwrap();
let b_shape = forge.get_shape(branch_b).unwrap();
assert_eq!(a_shape.parent, Some(base));
assert_eq!(b_shape.parent, Some(base));
}
#[test]
fn edge_same_structure_different_names() {
let forge = ShapeForge::new();
let s1 = forge.make_shape(EMPTY_SHAPE_ID, 1_000_070);
let s2 = forge.make_shape(s1, 1_000_080);
let s3 = forge.make_shape(EMPTY_SHAPE_ID, 1_000_090);
let s4 = forge.make_shape(s3, 1_000_100);
assert_ne!(s1, s3);
assert_ne!(s2, s4);
assert_eq!(forge.lookup_offset(s2, 1_000_070), Some(0));
assert_eq!(forge.lookup_offset(s4, 1_000_090), Some(0));
}
#[test]
fn concurrent_make_same_key() {
let forge = Arc::new(ShapeForge::new());
let key: StringIndex = 1_000_200;
let barrier = Arc::new(Barrier::new(2));
let f1 = Arc::clone(&forge);
let b1 = Arc::clone(&barrier);
let h1 = std::thread::spawn(move || {
b1.wait();
f1.make_shape(EMPTY_SHAPE_ID, key)
});
let f2 = Arc::clone(&forge);
let b2 = Arc::clone(&barrier);
let h2 = std::thread::spawn(move || {
b2.wait();
f2.make_shape(EMPTY_SHAPE_ID, key)
});
let id1 = h1.join().unwrap();
let id2 = h2.join().unwrap();
assert_eq!(id1, id2);
assert!(id1 > EMPTY_SHAPE_ID);
}
}