diff --git a/valuescript_compiler/src/asm.rs b/valuescript_compiler/src/asm.rs index a280faf..0736f75 100644 --- a/valuescript_compiler/src/asm.rs +++ b/valuescript_compiler/src/asm.rs @@ -1,4 +1,7 @@ -use std::hash::{Hash as HashTrait, Hasher}; +use std::{ + collections::HashMap, + hash::{Hash as HashTrait, Hasher}, +}; use num_bigint::BigInt; @@ -48,6 +51,24 @@ impl Module { assembly_lines.map(|s| s.to_string()).collect() } + + pub fn ptr_to_index(&self) -> HashMap { + let mut res = HashMap::::new(); + + for (i, defn) in self.definitions.iter().enumerate() { + res.insert(defn.pointer.clone(), i); + } + + res + } + + pub fn get<'a>( + &'a self, + ptr_to_index: &HashMap, + ptr: &Pointer, + ) -> &'a DefinitionContent { + &self.definitions[*ptr_to_index.get(ptr).unwrap()].content + } } impl std::fmt::Display for Module { @@ -112,7 +133,7 @@ impl std::fmt::Display for DefinitionContent { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] pub struct FnMeta { pub name: String, pub content_hashable: ContentHashable, @@ -150,7 +171,7 @@ impl std::fmt::Display for FnMeta { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] pub struct Hash(pub [u8; 32]); impl std::fmt::Display for Hash { @@ -167,7 +188,7 @@ impl std::fmt::Display for Hash { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] pub enum ContentHashable { #[default] Empty, @@ -228,6 +249,7 @@ impl std::fmt::Display for Function { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Class { + pub metadata: FnMeta, pub constructor: Value, pub prototype: Value, pub static_: Value, @@ -237,6 +259,7 @@ impl std::fmt::Display for Class { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { writeln!(f, "class {{")?; + writeln!(f, " metadata: {},", self.metadata)?; writeln!(f, " constructor: {},", self.constructor)?; write!(f, " prototype: ")?; diff --git a/valuescript_compiler/src/assembly_parser.rs b/valuescript_compiler/src/assembly_parser.rs index d118847..2181038 100644 --- a/valuescript_compiler/src/assembly_parser.rs +++ b/valuescript_compiler/src/assembly_parser.rs @@ -580,6 +580,11 @@ impl<'a> AssemblyParser<'a> { self.parse_exact("class {"); self.parse_optional_whitespace(); + self.parse_exact("metadata: "); + let metadata = self.assemble_fn_meta(); + self.parse_exact(","); + self.parse_optional_whitespace(); + self.parse_exact("constructor: "); let constructor = self.assemble_value(); self.parse_exact(","); @@ -598,6 +603,7 @@ impl<'a> AssemblyParser<'a> { self.parse_exact("}"); Class { + metadata, constructor, prototype, static_, diff --git a/valuescript_compiler/src/link_module.rs b/valuescript_compiler/src/link_module.rs index 3a414c9..1078f0a 100644 --- a/valuescript_compiler/src/link_module.rs +++ b/valuescript_compiler/src/link_module.rs @@ -386,155 +386,31 @@ pub fn collapse_pointers_of_pointers(module: &mut Module) { #[allow(clippy::ptr_arg)] fn calculate_content_hashes(module: &mut Module, _diagnostics: &mut Vec) { - let mut fn_to_meta = HashMap::::new(); + let ptr_to_index = module.ptr_to_index(); + + let mut ptr_to_src_meta = HashMap::)>::new(); let mut meta_to_fn = HashMap::::new(); - let mut src_and_deps_map = HashMap::)>::new(); for defn in &module.definitions { - match &defn.content { - DefinitionContent::Function(fn_) => { - if let Some(metadata) = &fn_.metadata { - fn_to_meta.insert(defn.pointer.clone(), metadata.clone()); - meta_to_fn.insert(metadata.clone(), defn.pointer.clone()); + if let Some(src_meta) = find_src_metadata(module, &ptr_to_index, defn) { + ptr_to_src_meta.insert(defn.pointer.clone(), src_meta); + + if let DefinitionContent::Function(fn_) = &defn.content { + if let Some(metadata_ptr) = &fn_.metadata { + meta_to_fn.insert(metadata_ptr.clone(), defn.pointer.clone()); } - } - DefinitionContent::FnMeta(fn_meta) => match &fn_meta.content_hashable { - ContentHashable::Empty => {} - ContentHashable::Src(src_hash, deps) => { - src_and_deps_map.insert(defn.pointer.clone(), (src_hash.clone(), deps.clone())); - } - ContentHashable::Content(_) => {} - }, - DefinitionContent::Value(_) => {} - DefinitionContent::Lazy(_) => {} + }; } } for defn in &mut module.definitions { match &mut defn.content { DefinitionContent::Function(_) => {} - DefinitionContent::FnMeta(fn_meta) => { - let fn_ptr = meta_to_fn.get(&defn.pointer).unwrap().clone(); - - let mut full_deps = vec![PointerOrBuiltin::Pointer(fn_ptr.clone())]; - let mut deps_included = HashSet::::new(); - deps_included.insert(PointerOrBuiltin::Pointer(fn_ptr.clone())); - - let mut i = 0; - - while i < full_deps.len() { - let dep = full_deps[i].clone(); - - let ptr_dep = match dep { - PointerOrBuiltin::Pointer(p) => p, - PointerOrBuiltin::Builtin(_) => { - i += 1; - continue; - } - }; - - let meta_ptr = fn_to_meta.get(&ptr_dep).unwrap(); - let (_, sub_deps) = src_and_deps_map.get(meta_ptr).unwrap(); - - for sub_dep in sub_deps { - match sub_dep { - Value::Pointer(p) => { - if deps_included.insert(PointerOrBuiltin::Pointer(p.clone())) { - full_deps.push(PointerOrBuiltin::Pointer(p.clone())); - } - } - Value::Builtin(b) => { - if deps_included.insert(PointerOrBuiltin::Builtin(b.clone())) { - full_deps.push(PointerOrBuiltin::Builtin(b.clone())); - } - } - _ => { - panic!("Expected sub_dep to be pointer or builtin") - } - } - } - - i += 1; - } - - let mut dep_to_index = HashMap::::new(); - - for (i, dep) in full_deps.iter().enumerate() { - dep_to_index.insert(dep.clone(), i); - } - - let mut links = Vec::>::new(); - - for dep in &full_deps { - let mut link = Vec::::new(); - - match dep { - PointerOrBuiltin::Pointer(ptr_dep) => { - let meta_ptr = fn_to_meta.get(ptr_dep).unwrap(); - let (_, sub_deps) = src_and_deps_map.get(meta_ptr).unwrap(); - - for sub_dep in sub_deps { - match sub_dep { - Value::Pointer(p) => { - let index = dep_to_index - .get(&PointerOrBuiltin::Pointer(p.clone())) - .unwrap(); - - link.push(*index); - } - Value::Builtin(b) => { - let index = dep_to_index - .get(&PointerOrBuiltin::Builtin(b.clone())) - .unwrap(); - - link.push(*index); - } - _ => { - panic!("Expected sub_dep to be pointer or builtin") - } - } - } - } - PointerOrBuiltin::Builtin(_) => {} - }; - - links.push(link); - } - - let mut content_trace = "{deps:".to_string(); - - content_trace.push_str(&make_array_string(&full_deps, |dep| match dep { - PointerOrBuiltin::Pointer(ptr_dep) => { - let meta_ptr = fn_to_meta.get(ptr_dep).unwrap(); - let (src_hash, _) = src_and_deps_map.get(meta_ptr).unwrap(); - src_hash.to_string() - } - PointerOrBuiltin::Builtin(b) => b.to_string(), - })); - - content_trace.push_str(",links:"); - - content_trace.push_str(&make_array_string(&links, |link| { - make_array_string(link, |i| i.to_string()) - })); - - content_trace.push('}'); - - // dbg!((fn_ptr, full_deps, links, content_trace)); - - let mut k = Keccak::v256(); - k.update(content_trace.as_bytes()); - - let mut content_hash_data = [0u8; 32]; - k.finalize(&mut content_hash_data); - - let content_hash = Hash(content_hash_data); - - *fn_meta = FnMeta { - name: take(&mut fn_meta.name), - content_hashable: ContentHashable::Content(content_hash), - }; - } + DefinitionContent::FnMeta(fn_meta) => update_metadata( + &ptr_to_src_meta, + meta_to_fn.get(&defn.pointer).unwrap(), + fn_meta, + ), DefinitionContent::Value(_) => {} DefinitionContent::Lazy(_) => {} } @@ -567,3 +443,163 @@ where result.push(']'); result } + +fn find_src_metadata( + module: &Module, + ptr_to_index: &HashMap, + defn: &Definition, +) -> Option<(Hash, Vec)> { + match &defn.content { + DefinitionContent::Function(fn_) => { + let metadata_ptr = match &fn_.metadata { + Some(ptr) => ptr, + None => return None, + }; + + let src_meta = match module.get(ptr_to_index, metadata_ptr) { + DefinitionContent::FnMeta(fn_meta) => match &fn_meta.content_hashable { + ContentHashable::Src(src_hash, deps) => (src_hash.clone(), deps.clone()), + _ => return None, + }, + _ => panic!("metadata_ptr did not point to metadata"), + }; + + Some(src_meta) + } + DefinitionContent::FnMeta(_fn_meta) => None, + DefinitionContent::Value(value) => match value { + Value::Class(class) => { + let src_meta = match &class.metadata.content_hashable { + ContentHashable::Src(src_hash, deps) => (src_hash.clone(), deps.clone()), + _ => return None, + }; + + Some(src_meta) + } + _ => None, + }, + DefinitionContent::Lazy(_) => None, + } +} + +fn update_metadata( + ptr_to_src_meta: &HashMap)>, + fn_ptr: &Pointer, + fn_meta: &mut FnMeta, +) { + let mut full_deps = vec![PointerOrBuiltin::Pointer(fn_ptr.clone())]; + let mut deps_included = HashSet::::new(); + deps_included.insert(PointerOrBuiltin::Pointer(fn_ptr.clone())); + + let mut i = 0; + + while i < full_deps.len() { + let dep = full_deps[i].clone(); + + let ptr_dep = match dep { + PointerOrBuiltin::Pointer(p) => p, + PointerOrBuiltin::Builtin(_) => { + i += 1; + continue; + } + }; + + let (_, sub_deps) = ptr_to_src_meta.get(&ptr_dep).unwrap(); + + for sub_dep in sub_deps { + match sub_dep { + Value::Pointer(p) => { + if deps_included.insert(PointerOrBuiltin::Pointer(p.clone())) { + full_deps.push(PointerOrBuiltin::Pointer(p.clone())); + } + } + Value::Builtin(b) => { + if deps_included.insert(PointerOrBuiltin::Builtin(b.clone())) { + full_deps.push(PointerOrBuiltin::Builtin(b.clone())); + } + } + _ => { + panic!("Expected sub_dep to be pointer or builtin") + } + } + } + + i += 1; + } + + let mut dep_to_index = HashMap::::new(); + + for (i, dep) in full_deps.iter().enumerate() { + dep_to_index.insert(dep.clone(), i); + } + + let mut links = Vec::>::new(); + + for dep in &full_deps { + let mut link = Vec::::new(); + + match dep { + PointerOrBuiltin::Pointer(ptr_dep) => { + let (_, sub_deps) = ptr_to_src_meta.get(ptr_dep).unwrap(); + + for sub_dep in sub_deps { + match sub_dep { + Value::Pointer(p) => { + let index = dep_to_index + .get(&PointerOrBuiltin::Pointer(p.clone())) + .unwrap(); + + link.push(*index); + } + Value::Builtin(b) => { + let index = dep_to_index + .get(&PointerOrBuiltin::Builtin(b.clone())) + .unwrap(); + + link.push(*index); + } + _ => { + panic!("Expected sub_dep to be pointer or builtin") + } + } + } + } + PointerOrBuiltin::Builtin(_) => {} + }; + + links.push(link); + } + + let mut content_trace = "{deps:".to_string(); + + content_trace.push_str(&make_array_string(&full_deps, |dep| match dep { + PointerOrBuiltin::Pointer(ptr_dep) => { + let (src_hash, _) = ptr_to_src_meta.get(ptr_dep).unwrap(); + src_hash.to_string() + } + PointerOrBuiltin::Builtin(b) => b.to_string(), + })); + + content_trace.push_str(",links:"); + + content_trace.push_str(&make_array_string(&links, |link| { + make_array_string(link, |i| i.to_string()) + })); + + content_trace.push('}'); + + // dbg!((fn_ptr, full_deps, links, content_trace)); + + let mut k = Keccak::v256(); + k.update(content_trace.as_bytes()); + + let mut content_hash_data = [0u8; 32]; + k.finalize(&mut content_hash_data); + + let content_hash = Hash(content_hash_data); + + *fn_meta = FnMeta { + name: take(&mut fn_meta.name), + content_hashable: ContentHashable::Content(content_hash), + }; +} diff --git a/valuescript_compiler/src/module_compiler.rs b/valuescript_compiler/src/module_compiler.rs index a7f62ee..20ad460 100644 --- a/valuescript_compiler/src/module_compiler.rs +++ b/valuescript_compiler/src/module_compiler.rs @@ -8,8 +8,8 @@ use swc_ecma_ast::EsVersion; use swc_ecma_parser::{Syntax, TsConfig}; use crate::asm::{ - Class, Definition, DefinitionContent, FnLine, Instruction, Lazy, Module, Number, Object, Pointer, - Register, Value, + Class, ContentHashable, Definition, DefinitionContent, FnLine, FnMeta, Instruction, Lazy, Module, + Number, Object, Pointer, Register, Value, }; use crate::diagnostic::{Diagnostic, DiagnosticContainer, DiagnosticReporter}; use crate::expression_compiler::{CompiledExpression, ExpressionCompiler}; @@ -18,6 +18,7 @@ use crate::ident::Ident; use crate::name_allocator::{ident_from_str, NameAllocator}; use crate::scope::OwnerId; use crate::scope_analysis::{class_to_owner_id, ScopeAnalysis}; +use crate::src_hash::src_hash; use crate::static_expression_compiler::StaticExpressionCompiler; struct DiagnosticCollector { @@ -877,6 +878,13 @@ impl ModuleCompiler { } let class_value = Value::Class(Box::new(Class { + metadata: FnMeta { + name: ident.map_or_else(String::new, |ident| ident.sym.to_string()), + content_hashable: ContentHashable::Src( + src_hash(&self.source, class.span), + self.scope_analysis.get_deps(class.span), + ), + }, constructor, prototype: Value::Object(Box::new(prototype)), static_: Value::Object(Box::new(static_)), diff --git a/valuescript_compiler/src/optimization/kal.rs b/valuescript_compiler/src/optimization/kal.rs index a029719..09c55ac 100644 --- a/valuescript_compiler/src/optimization/kal.rs +++ b/valuescript_compiler/src/optimization/kal.rs @@ -12,7 +12,7 @@ use std::{ }; use crate::{ - asm::{self, Builtin, FnLine, Function, Number, Pointer, Register, Value}, + asm::{self, Builtin, FnLine, FnMeta, Function, Number, Pointer, Register, Value}, instruction::Instruction, name_allocator::RegAllocator, }; @@ -72,6 +72,7 @@ pub struct KFunction { #[derive(Clone, Debug)] pub struct Class { + pub metadata: FnMeta, pub constructor: Kal, pub prototype: Kal, pub static_: Kal, @@ -136,6 +137,7 @@ impl Kal { .collect(), })), Value::Class(class) => Kal::Class(Box::new(Class { + metadata: class.metadata.clone(), constructor: Kal::from_value(&class.constructor), prototype: Kal::from_value(&class.prototype), static_: Kal::from_value(&class.static_), @@ -209,6 +211,7 @@ impl Kal { }))), Kal::Function(_) => None, Kal::Class(class) => Some(Value::Class(Box::new(asm::Class { + metadata: class.metadata.clone(), constructor: class.constructor.try_to_value()?, prototype: class.prototype.try_to_value()?, static_: class.static_.try_to_value()?, @@ -783,6 +786,7 @@ impl FnState { Kal::Object(Box::new(Object { properties })) } Value::Class(class) => Kal::Class(Box::new(Class { + metadata: class.metadata.clone(), constructor: self.eval_arg(&mut class.constructor), prototype: self.eval_arg(&mut class.prototype), static_: self.eval_arg(&mut class.static_),