This commit is contained in:
Andrew Morris
2023-08-15 12:49:31 +10:00
parent dabb02a48b
commit 1cac81bc44
5 changed files with 223 additions and 146 deletions

View File

@@ -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<Pointer, usize> {
let mut res = HashMap::<Pointer, usize>::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<Pointer, usize>,
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: ")?;

View File

@@ -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_,

View File

@@ -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<Diagnostic>) {
let mut fn_to_meta = HashMap::<Pointer, Pointer>::new();
let ptr_to_index = module.ptr_to_index();
let mut ptr_to_src_meta = HashMap::<Pointer, (Hash, Vec<Value>)>::new();
let mut meta_to_fn = HashMap::<Pointer, Pointer>::new();
let mut src_and_deps_map = HashMap::<Pointer, (Hash, Vec<Value>)>::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::<PointerOrBuiltin>::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::<PointerOrBuiltin, usize>::new();
for (i, dep) in full_deps.iter().enumerate() {
dep_to_index.insert(dep.clone(), i);
}
let mut links = Vec::<Vec<usize>>::new();
for dep in &full_deps {
let mut link = Vec::<usize>::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<Pointer, usize>,
defn: &Definition,
) -> Option<(Hash, Vec<Value>)> {
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<Pointer, (Hash, Vec<Value>)>,
fn_ptr: &Pointer,
fn_meta: &mut FnMeta,
) {
let mut full_deps = vec![PointerOrBuiltin::Pointer(fn_ptr.clone())];
let mut deps_included = HashSet::<PointerOrBuiltin>::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::<PointerOrBuiltin, usize>::new();
for (i, dep) in full_deps.iter().enumerate() {
dep_to_index.insert(dep.clone(), i);
}
let mut links = Vec::<Vec<usize>>::new();
for dep in &full_deps {
let mut link = Vec::<usize>::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),
};
}

View File

@@ -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_)),

View File

@@ -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_),