From fe3331d995b892ccadceec3ae0404aabeb9fca17 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Fri, 5 Jun 2026 23:53:30 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=9B=86=E4=B8=AD=20AST=20?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E9=80=BB=E8=BE=91=E5=AE=9E=E7=8E=B0=E5=B9=B6?= =?UTF-8?q?=E6=B8=85=E7=90=86=E6=97=A0=E5=85=B3=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 3 +- crates/oxide_compiler/Cargo.toml | 3 + crates/oxide_compiler/src/cache.rs | 133 ------------------ crates/oxide_compiler/src/compiler.rs | 89 ++++++++++++ crates/oxide_compiler/src/lib.rs | 1 - crates/oxide_compiler/tests/compiler_tests.rs | 27 ++-- crates/oxide_kernel/Cargo.toml | 1 - crates/oxide_kernel/src/code_forge.rs | 85 +---------- crates/oxide_vm/Cargo.toml | 1 - 9 files changed, 109 insertions(+), 234 deletions(-) delete mode 100644 crates/oxide_compiler/src/cache.rs diff --git a/Cargo.lock b/Cargo.lock index 81a6ad33..24c879e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -771,6 +771,7 @@ dependencies = [ name = "oxide_compiler" version = "0.1.0" dependencies = [ + "oxide_kernel", "oxide_parser", "rustc-hash", "serde", @@ -781,7 +782,6 @@ dependencies = [ name = "oxide_kernel" version = "0.1.0" dependencies = [ - "bumpalo", "dashmap", "hashbrown 0.14.5", "oxide_compiler", @@ -822,7 +822,6 @@ dependencies = [ "oxide_parser", "oxide_types", "proptest", - "rustc-hash", "ryu", ] diff --git a/crates/oxide_compiler/Cargo.toml b/crates/oxide_compiler/Cargo.toml index ee8c8019..edf728ec 100644 --- a/crates/oxide_compiler/Cargo.toml +++ b/crates/oxide_compiler/Cargo.toml @@ -11,3 +11,6 @@ oxide_parser = { path = "../oxide_parser" } serde.workspace = true serde_json.workspace = true rustc-hash.workspace = true + +[dev-dependencies] +oxide_kernel = { path = "../oxide_kernel" } diff --git a/crates/oxide_compiler/src/cache.rs b/crates/oxide_compiler/src/cache.rs deleted file mode 100644 index 177af766..00000000 --- a/crates/oxide_compiler/src/cache.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::collections::HashMap; -use std::hash::{Hash, Hasher}; -use std::sync::Arc; - -use oxide_parser::{Expression, Statement}; -use rustc_hash::FxHasher; - -use crate::compiler::Compiler; -use crate::module::CompiledModule; - -/// Hash AST structure — strips identifiers and literal values. -/// Two scripts with different variable names but identical tree shape -/// produce the same hash, enabling structural cache reuse. -pub fn structural_hash(program: &oxide_parser::Program) -> u64 { - let mut h = FxHasher::default(); - - for stmt in &program.body { - hash_statement(stmt, &mut h); - } - - h.finish() -} - -fn hash_statement(stmt: &Statement, h: &mut FxHasher) { - match stmt { - Statement::ExpressionStatement(es) => { - 0u8.hash(h); - hash_expression(&es.expression, h); - } - Statement::VariableDeclaration(decl) => { - 1u8.hash(h); - (decl.declarations.len() as u32).hash(h); - } - Statement::ReturnStatement(ret) => { - 2u8.hash(h); - if let Some(arg) = &ret.argument { - hash_expression(arg, h); - } - } - Statement::IfStatement(ifs) => { - 3u8.hash(h); - hash_expression(&ifs.test, h); - hash_statement(&ifs.consequent, h); - if let Some(alt) = &ifs.alternate { - hash_statement(alt, h); - } - } - Statement::WhileStatement(wh) => { - 4u8.hash(h); - hash_expression(&wh.test, h); - hash_statement(&wh.body, h); - } - Statement::ForStatement(fr) => { - 5u8.hash(h); - hash_statement(&fr.body, h); - } - Statement::BlockStatement(block) => { - 6u8.hash(h); - for s in &block.body { - hash_statement(s, h); - } - } - _ => { - std::mem::discriminant(stmt).hash(h); - } - } -} - -fn hash_expression(expr: &Expression, h: &mut FxHasher) { - match expr { - Expression::BinaryExpression(bin) => { - 0u8.hash(h); - std::mem::discriminant(&bin.operator).hash(h); - hash_expression(&bin.left, h); - hash_expression(&bin.right, h); - } - Expression::UnaryExpression(un) => { - 1u8.hash(h); - std::mem::discriminant(&un.operator).hash(h); - hash_expression(&un.argument, h); - } - Expression::CallExpression(_) => { - 2u8.hash(h); - } - Expression::LogicalExpression(log) => { - 3u8.hash(h); - std::mem::discriminant(&log.operator).hash(h); - hash_expression(&log.left, h); - hash_expression(&log.right, h); - } - _ => { - std::mem::discriminant(expr).hash(h); - // strip literal values — only node type matters for structural identity - } - } -} - -/// Local compilation cache — Phase 4 in-memory HashMap. -/// Migrated to OxideKernel CodeForge (DashMap) in Phase 7. -pub struct CodeCache { - map: HashMap>, -} - -impl CodeCache { - pub fn new() -> Self { - Self { - map: HashMap::new(), - } - } - - pub fn get_or_compile( - &mut self, - program: &oxide_parser::Program, - compiler: &Compiler, - ) -> Result, String> { - let hash = structural_hash(program); - - if let Some(module) = self.map.get(&hash) { - return Ok(Arc::clone(module)); - } - - let module = compiler.compile(program)?; - let module = Arc::new(module); - self.map.insert(hash, Arc::clone(&module)); - Ok(module) - } -} - -impl Default for CodeCache { - fn default() -> Self { - Self::new() - } -} diff --git a/crates/oxide_compiler/src/compiler.rs b/crates/oxide_compiler/src/compiler.rs index 5d7e983e..f38b6eaa 100644 --- a/crates/oxide_compiler/src/compiler.rs +++ b/crates/oxide_compiler/src/compiler.rs @@ -501,3 +501,92 @@ impl Compiler { } } } + +pub fn structural_hash(program: &oxide_parser::Program) -> u64 { + use std::hash::Hasher; + + let mut h = rustc_hash::FxHasher::default(); + + for stmt in &program.body { + hash_statement(stmt, &mut h); + } + + h.finish() +} + +fn hash_statement(stmt: &Statement, h: &mut rustc_hash::FxHasher) { + use std::hash::Hash; + + match stmt { + Statement::ExpressionStatement(es) => { + 0u8.hash(h); + hash_expression(&es.expression, h); + } + Statement::VariableDeclaration(decl) => { + 1u8.hash(h); + (decl.declarations.len() as u32).hash(h); + } + Statement::ReturnStatement(ret) => { + 2u8.hash(h); + if let Some(arg) = &ret.argument { + hash_expression(arg, h); + } + } + Statement::IfStatement(ifs) => { + 3u8.hash(h); + hash_expression(&ifs.test, h); + hash_statement(&ifs.consequent, h); + if let Some(alt) = &ifs.alternate { + hash_statement(alt, h); + } + } + Statement::WhileStatement(wh) => { + 4u8.hash(h); + hash_expression(&wh.test, h); + hash_statement(&wh.body, h); + } + Statement::ForStatement(fr) => { + 5u8.hash(h); + hash_statement(&fr.body, h); + } + Statement::BlockStatement(block) => { + 6u8.hash(h); + for s in &block.body { + hash_statement(s, h); + } + } + _ => { + std::mem::discriminant(stmt).hash(h); + } + } +} + +fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) { + use std::hash::Hash; + + match expr { + Expression::BinaryExpression(bin) => { + 0u8.hash(h); + std::mem::discriminant(&bin.operator).hash(h); + hash_expression(&bin.left, h); + hash_expression(&bin.right, h); + } + Expression::UnaryExpression(un) => { + 1u8.hash(h); + std::mem::discriminant(&un.operator).hash(h); + hash_expression(&un.argument, h); + } + Expression::CallExpression(_) => { + 2u8.hash(h); + } + Expression::LogicalExpression(log) => { + 3u8.hash(h); + std::mem::discriminant(&log.operator).hash(h); + hash_expression(&log.left, h); + hash_expression(&log.right, h); + } + _ => { + std::mem::discriminant(expr).hash(h); + } + } +} diff --git a/crates/oxide_compiler/src/lib.rs b/crates/oxide_compiler/src/lib.rs index fc8009ca..00ab9d87 100644 --- a/crates/oxide_compiler/src/lib.rs +++ b/crates/oxide_compiler/src/lib.rs @@ -1,6 +1,5 @@ #![doc = "OxideJS - AST to bytecode compiler"] -pub mod cache; pub mod compiler; pub mod module; pub mod opcode; diff --git a/crates/oxide_compiler/tests/compiler_tests.rs b/crates/oxide_compiler/tests/compiler_tests.rs index 141b9d25..4aa86335 100644 --- a/crates/oxide_compiler/tests/compiler_tests.rs +++ b/crates/oxide_compiler/tests/compiler_tests.rs @@ -1,6 +1,6 @@ -use oxide_compiler::cache::CodeCache; use oxide_compiler::compiler::Compiler; use oxide_compiler::opcode::{self, OpCode}; +use oxide_kernel::code_forge::CodeForge; use oxide_parser::Allocator; fn compile_source(source: &str) -> oxide_compiler::module::CompiledModule { @@ -13,7 +13,7 @@ fn compile_source(source: &str) -> oxide_compiler::module::CompiledModule { fn parse_to_hash(source: &str) -> u64 { let allocator = Allocator::default(); let program = oxide_parser::parse(&allocator, source).expect("parse failed"); - oxide_compiler::cache::structural_hash(&program) + oxide_compiler::compiler::structural_hash(&program) } #[test] @@ -81,31 +81,34 @@ fn compile_binary_ops() { } #[test] -fn structural_cache_hit() { +fn structural_hash_hit() { + let forge = CodeForge::new(); + let compiler = Compiler::new(); let allocator = Allocator::default(); let program = oxide_parser::parse(&allocator, "1 + 2").expect("parse failed"); - let compiler = Compiler::new(); - let mut cache = CodeCache::new(); - let m1 = cache + let m1 = forge .get_or_compile(&program, &compiler) - .expect("compile failed"); - let m2 = cache + .expect("first compile"); + let m2 = forge .get_or_compile(&program, &compiler) - .expect("compile failed"); + .expect("second compile"); - assert_eq!(m1.bytecode, m2.bytecode); + assert_eq!( + (m1.bytecode.len(), m1.n_registers), + (m2.bytecode.len(), m2.n_registers) + ); } #[test] -fn structural_cache_same_shape() { +fn structural_hash_same_shape() { let hash_a = parse_to_hash("var x = 1 + 2; var y = x;"); let hash_b = parse_to_hash("var a = 3 + 4; var b = a;"); assert_eq!(hash_a, hash_b); } #[test] -fn structural_cache_different_shape() { +fn structural_hash_different_shape() { let hash_a = parse_to_hash("1 + 2"); let hash_b = parse_to_hash("1 + 2 * 3"); assert_ne!(hash_a, hash_b); diff --git a/crates/oxide_kernel/Cargo.toml b/crates/oxide_kernel/Cargo.toml index b04baf31..80f7a838 100644 --- a/crates/oxide_kernel/Cargo.toml +++ b/crates/oxide_kernel/Cargo.toml @@ -10,7 +10,6 @@ description = "OxideJS - Shared kernel (CodeForge, ShapeForge, PropForge, String oxide_compiler = { path = "../oxide_compiler" } oxide_parser = { path = "../oxide_parser" } oxide_types = { path = "../oxide_types" } -bumpalo.workspace = true dashmap.workspace = true hashbrown.workspace = true rustc-hash.workspace = true diff --git a/crates/oxide_kernel/src/code_forge.rs b/crates/oxide_kernel/src/code_forge.rs index a9fe35d3..9d7bdf28 100644 --- a/crates/oxide_kernel/src/code_forge.rs +++ b/crates/oxide_kernel/src/code_forge.rs @@ -1,94 +1,11 @@ -use std::hash::{Hash, Hasher}; use std::sync::Arc; use dashmap::DashMap; use oxide_compiler::compiler::Compiler; use oxide_compiler::module::CompiledModule; -use oxide_parser::{Expression, Statement}; -pub fn structural_hash(program: &oxide_parser::Program) -> u64 { - let mut h = rustc_hash::FxHasher::default(); - - for stmt in &program.body { - hash_statement(stmt, &mut h); - } - - h.finish() -} - -fn hash_statement(stmt: &Statement, h: &mut rustc_hash::FxHasher) { - match stmt { - Statement::ExpressionStatement(es) => { - 0u8.hash(h); - hash_expression(&es.expression, h); - } - Statement::VariableDeclaration(decl) => { - 1u8.hash(h); - (decl.declarations.len() as u32).hash(h); - } - Statement::ReturnStatement(ret) => { - 2u8.hash(h); - if let Some(arg) = &ret.argument { - hash_expression(arg, h); - } - } - Statement::IfStatement(ifs) => { - 3u8.hash(h); - hash_expression(&ifs.test, h); - hash_statement(&ifs.consequent, h); - if let Some(alt) = &ifs.alternate { - hash_statement(alt, h); - } - } - Statement::WhileStatement(wh) => { - 4u8.hash(h); - hash_expression(&wh.test, h); - hash_statement(&wh.body, h); - } - Statement::ForStatement(fr) => { - 5u8.hash(h); - hash_statement(&fr.body, h); - } - Statement::BlockStatement(block) => { - 6u8.hash(h); - for s in &block.body { - hash_statement(s, h); - } - } - _ => { - std::mem::discriminant(stmt).hash(h); - } - } -} - -fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher) { - match expr { - Expression::BinaryExpression(bin) => { - 0u8.hash(h); - std::mem::discriminant(&bin.operator).hash(h); - hash_expression(&bin.left, h); - hash_expression(&bin.right, h); - } - Expression::UnaryExpression(un) => { - 1u8.hash(h); - std::mem::discriminant(&un.operator).hash(h); - hash_expression(&un.argument, h); - } - Expression::CallExpression(_) => { - 2u8.hash(h); - } - Expression::LogicalExpression(log) => { - 3u8.hash(h); - std::mem::discriminant(&log.operator).hash(h); - hash_expression(&log.left, h); - hash_expression(&log.right, h); - } - _ => { - std::mem::discriminant(expr).hash(h); - } - } -} +pub use oxide_compiler::compiler::structural_hash; pub struct CodeForge { map: DashMap>, diff --git a/crates/oxide_vm/Cargo.toml b/crates/oxide_vm/Cargo.toml index e29058ad..cd95160b 100644 --- a/crates/oxide_vm/Cargo.toml +++ b/crates/oxide_vm/Cargo.toml @@ -10,7 +10,6 @@ description = "OxideJS - Register-based VM with epoch arena memory" oxide_compiler = { path = "../oxide_compiler" } oxide_kernel = { path = "../oxide_kernel" } oxide_types = { path = "../oxide_types" } -rustc-hash.workspace = true fast-float.workspace = true ryu.workspace = true