feat: VM 复用 kernel 字符串共享池

This commit is contained in:
爱特每羊队
2026-06-05 23:04:40 +08:00
parent 39c9b9c983
commit 1a4487bf92
+22 -45
View File
@@ -1,10 +1,13 @@
use std::collections::HashMap; #![allow(clippy::arc_with_non_send_sync)]
use std::sync::Arc;
use oxide_compiler::compiler::Constant; use oxide_compiler::compiler::Constant;
use oxide_compiler::module::CompiledModule; use oxide_compiler::module::CompiledModule;
use oxide_compiler::opcode::{self, OpCode}; use oxide_compiler::opcode::{self, OpCode};
use crate::coercion; use crate::coercion;
use oxide_kernel::kernel::{KernelConfig, OxideKernel};
use oxide_types::mem::{Epoch, P}; use oxide_types::mem::{Epoch, P};
use oxide_types::object::JsObject; use oxide_types::object::JsObject;
use oxide_types::shape::{self, EMPTY_SHAPE_ID}; use oxide_types::shape::{self, EMPTY_SHAPE_ID};
@@ -22,8 +25,8 @@ pub struct Vm {
bytecode: Vec<opcode::Instr>, bytecode: Vec<opcode::Instr>,
constants: Vec<JsValue>, constants: Vec<JsValue>,
frames: Vec<CallFrame>, frames: Vec<CallFrame>,
string_table: HashMap<String, u32>, kernel: Arc<OxideKernel>,
string_reverse: Vec<String>, interned_strings: Vec<u32>,
pub epoch: Epoch, pub epoch: Epoch,
pub object_prototype: P<JsObject>, pub object_prototype: P<JsObject>,
} }
@@ -36,40 +39,41 @@ impl Vm {
bytecode: Vec::new(), bytecode: Vec::new(),
constants: Vec::new(), constants: Vec::new(),
frames: Vec::with_capacity(128), frames: Vec::with_capacity(128),
string_table: HashMap::with_capacity(64), kernel: Arc::new(OxideKernel::new(KernelConfig::minimal())),
string_reverse: Vec::with_capacity(64), interned_strings: Vec::new(),
epoch: Epoch::new(), epoch: Epoch::new(),
object_prototype: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())), object_prototype: P::new(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())),
} }
} }
pub fn with_kernel(kernel: Arc<OxideKernel>) -> Self {
let mut vm = Self::new();
vm.kernel = Arc::clone(&kernel);
vm.object_prototype = P::clone(&kernel.builtin_world().object_proto);
vm
}
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.regs = [JsValue::undefined(); 256]; self.regs = [JsValue::undefined(); 256];
self.pc = 0; self.pc = 0;
self.bytecode.clear(); self.bytecode.clear();
self.constants.clear(); self.constants.clear();
self.frames.clear(); self.frames.clear();
self.string_table.clear();
self.string_reverse.clear();
self.epoch.reset(); self.epoch.reset();
self.interned_strings.clear();
} }
pub fn intern(&mut self, s: &str) -> JsValue { pub fn intern(&mut self, s: &str) -> JsValue {
if let Some(&idx) = self.string_table.get(s) { let (idx, hash) = self.kernel.string_forge().intern(s);
return JsValue::string(idx, hash16(s)); self.interned_strings.push(idx);
} JsValue::string(idx, hash)
let idx = self.string_reverse.len() as u32;
self.string_reverse.push(s.to_string());
self.string_table.insert(s.to_string(), idx);
JsValue::string(idx, hash16(s))
} }
pub fn lookup_str(&self, val: JsValue) -> Option<&str> { pub fn lookup_str(&self, val: JsValue) -> Option<String> {
if !val.is_string() { if !val.is_string() {
return None; return None;
} }
let idx = val.as_string_index() as usize; self.kernel.string_forge().lookup(val.as_string_index())
self.string_reverse.get(idx).map(|s| s.as_str())
} }
fn resolve_property(&self, obj: &JsObject, prop_name_si: u32) -> Option<JsValue> { fn resolve_property(&self, obj: &JsObject, prop_name_si: u32) -> Option<JsValue> {
@@ -95,32 +99,12 @@ impl Vm {
} }
pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> { pub fn run(&mut self, module: &CompiledModule) -> Result<JsValue, String> {
self.string_table.clear();
self.string_reverse.clear();
let string_entries: Vec<String> = module
.constants
.iter()
.filter_map(|c| {
if let Constant::String(s) = c {
Some(s.clone())
} else {
None
}
})
.collect();
for s in &string_entries {
self.intern(s);
}
self.constants = module self.constants = module
.constants .constants
.iter() .iter()
.map(|c| match c { .map(|c| match c {
Constant::Number(v) => JsValue::float(*v), Constant::Number(v) => JsValue::float(*v),
Constant::String(s) => { Constant::String(s) => self.intern(s),
let idx = self.string_table.get(s.as_str()).copied().unwrap_or(0);
JsValue::string(idx, hash16(s))
}
Constant::Boolean(b) => JsValue::bool(*b), Constant::Boolean(b) => JsValue::bool(*b),
Constant::Null => JsValue::null(), Constant::Null => JsValue::null(),
Constant::Undefined => JsValue::undefined(), Constant::Undefined => JsValue::undefined(),
@@ -505,10 +489,3 @@ impl Default for Vm {
Self::new() Self::new()
} }
} }
fn hash16(s: &str) -> u16 {
use std::hash::{Hash, Hasher};
let mut h = rustc_hash::FxHasher::default();
s.hash(&mut h);
(h.finish() >> 48) as u16
}