This commit is contained in:
Andrew Morris
2023-08-15 11:03:33 +10:00
parent 3ffafda8d2
commit a7db195c8a
10 changed files with 265 additions and 72 deletions

View File

@@ -131,13 +131,7 @@ impl std::fmt::Display for FnMeta {
match &self.content_hashable {
ContentHashable::Empty => {}
ContentHashable::Src(src_hash, deps) => {
write!(f, " srcHash: 0x")?;
for b in src_hash {
write!(f, "{:02x}", b)?;
}
writeln!(f, ",")?;
writeln!(f, " srcHash: {},", src_hash)?;
writeln!(
f,
@@ -147,14 +141,8 @@ impl std::fmt::Display for FnMeta {
}
)?;
}
ContentHashable::Hash(content_hash) => {
write!(f, " contentHash: 0x")?;
for b in content_hash {
write!(f, "{:02x}", b)?;
}
writeln!(f, ",")?;
ContentHashable::Content(content_hash) => {
writeln!(f, " contentHash: {},", content_hash)?;
}
}
@@ -162,12 +150,29 @@ impl std::fmt::Display for FnMeta {
}
}
#[derive(Debug, Clone, Default)]
pub struct Hash(pub [u8; 32]);
impl std::fmt::Display for Hash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#")?;
let Hash(data) = self;
for b in data {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
#[derive(Debug, Clone, Default)]
pub enum ContentHashable {
#[default]
Empty,
Src([u8; 32], Vec<Value>),
Hash([u8; 32]),
Src(Hash, Vec<Value>),
Content(Hash),
}
#[derive(Hash, PartialEq, Eq, Clone, Debug, PartialOrd, Ord)]

View File

@@ -9,7 +9,7 @@ use valuescript_common::BuiltinName;
use crate::asm::{
Array, Builtin, Class, ContentHashable, Definition, DefinitionContent, FnLine, FnMeta, Function,
Instruction, Label, LabelRef, Lazy, Module, Number, Object, Pointer, Register, Value,
Hash, Instruction, Label, LabelRef, Lazy, Module, Number, Object, Pointer, Register, Value,
};
pub fn assemble(module: &Module) -> Vec<u8> {
@@ -142,7 +142,9 @@ impl Assembler {
ContentHashable::Src(src_hash, deps) => {
self.output.push(0x01);
for b in src_hash {
let Hash(src_hash_data) = src_hash;
for b in src_hash_data {
self.output.push(*b);
}
@@ -152,10 +154,12 @@ impl Assembler {
self.value(dep);
}
}
ContentHashable::Hash(content_hash) => {
ContentHashable::Content(content_hash) => {
self.output.push(0x02);
for b in content_hash {
let Hash(content_hash_data) = content_hash;
for b in content_hash_data {
self.output.push(*b);
}
}

View File

@@ -6,7 +6,8 @@ use valuescript_common::{InstructionByte, BUILTIN_NAMES};
use crate::asm::{
Array, Builtin, Class, ContentHashable, Definition, DefinitionContent, ExportStar, FnLine,
FnMeta, Function, Instruction, Label, LabelRef, Module, Number, Object, Pointer, Register, Value,
FnMeta, Function, Hash, Instruction, Label, LabelRef, Module, Number, Object, Pointer, Register,
Value,
};
pub struct AssemblyParser<'a> {
@@ -561,7 +562,7 @@ impl<'a> AssemblyParser<'a> {
self.parse_exact(",");
self.parse_optional_whitespace();
break 'b ContentHashable::Hash(content_hash);
break 'b ContentHashable::Content(content_hash);
}
panic!("{}", self.render_pos(-1, "Expected ContentHashable"));
@@ -1124,8 +1125,8 @@ impl<'a> AssemblyParser<'a> {
}
}
fn assemble_hash(&mut self) -> [u8; 32] {
self.parse_exact("0x");
fn assemble_hash(&mut self) -> Hash {
self.parse_exact("#");
let mut res = [0u8; 32];
@@ -1136,7 +1137,7 @@ impl<'a> AssemblyParser<'a> {
}
}
res
Hash(res)
}
fn assemble_hex_byte(&mut self) -> Option<u8> {

View File

@@ -1,8 +1,11 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use std::mem::swap;
use std::mem::{swap, take};
use tiny_keccak::{Hasher, Keccak};
use crate::asm::{
Definition, DefinitionContent, ExportStar, FnLine, Instruction, Object, Pointer, Value,
Builtin, ContentHashable, Definition, DefinitionContent, ExportStar, FnLine, FnMeta, Hash,
Instruction, Object, Pointer, Value,
};
use crate::gather_modules::PathAndModule;
use crate::import_pattern::{ImportKind, ImportPattern};
@@ -109,6 +112,9 @@ pub fn link_module(
&mut result.diagnostics,
);
collapse_pointers_of_pointers(&mut path_and_module.module);
calculate_content_hashes(&mut path_and_module.module, &mut result.diagnostics);
optimize(&mut path_and_module.module, &mut pointer_allocator);
result.module = Some(path_and_module.module);
@@ -346,3 +352,218 @@ fn flatten_export_star(
obj
}
pub fn collapse_pointers_of_pointers(module: &mut Module) {
let mut double_pointer_map = HashMap::<Pointer, Pointer>::new();
for definition in &mut module.definitions {
let pointer = match &definition.content {
DefinitionContent::Value(Value::Pointer(pointer)) => pointer,
_ => continue,
};
double_pointer_map.insert(definition.pointer.clone(), pointer.clone());
}
visit_pointers(module, |visitation| match visitation {
PointerVisitation::Definition(_) => {}
PointerVisitation::Export(pointer) | PointerVisitation::Reference(_, pointer) => {
let mut mapped_pointer: &Pointer = pointer;
loop {
if let Some(new_pointer) = double_pointer_map.get(mapped_pointer) {
mapped_pointer = new_pointer;
continue;
}
break;
}
*pointer = mapped_pointer.clone();
}
});
}
#[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 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());
}
}
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::Value(_) => {}
DefinitionContent::Lazy(_) => {}
}
}
}
#[derive(Eq, Hash, PartialEq, Clone, Debug)]
enum PointerOrBuiltin {
Pointer(Pointer),
Builtin(Builtin),
}
fn make_array_string<T, F, S>(seq: S, to_string_fn: F) -> String
where
S: IntoIterator<Item = T>,
F: Fn(T) -> String,
{
let mut result = "[".to_string();
let mut iter = seq.into_iter();
if let Some(first_item) = iter.next() {
result.push_str(&to_string_fn(first_item));
for item in iter {
result.push(',');
result.push_str(&to_string_fn(item));
}
}
result.push(']');
result
}

View File

@@ -1,37 +0,0 @@
use std::collections::HashMap;
use crate::{
asm::{DefinitionContent, Module, Pointer, Value},
visit_pointers::{visit_pointers, PointerVisitation},
};
pub fn collapse_pointers_of_pointers(module: &mut Module) {
let mut double_pointer_map = HashMap::<Pointer, Pointer>::new();
for definition in &mut module.definitions {
let pointer = match &definition.content {
DefinitionContent::Value(Value::Pointer(pointer)) => pointer,
_ => continue,
};
double_pointer_map.insert(definition.pointer.clone(), pointer.clone());
}
visit_pointers(module, |visitation| match visitation {
PointerVisitation::Definition(_) => {}
PointerVisitation::Export(pointer) | PointerVisitation::Reference(_, pointer) => {
let mut mapped_pointer: &Pointer = pointer;
loop {
if let Some(new_pointer) = double_pointer_map.get(mapped_pointer) {
mapped_pointer = new_pointer;
continue;
}
break;
}
*pointer = mapped_pointer.clone();
}
});
}

View File

@@ -1,4 +1,3 @@
mod collapse_pointers_of_pointers;
mod extract_constants;
pub mod kal;
mod optimize;

View File

@@ -1,7 +1,6 @@
use crate::asm::Module;
use crate::name_allocator::NameAllocator;
use super::collapse_pointers_of_pointers::collapse_pointers_of_pointers;
use super::extract_constants::extract_constants;
use super::reduce_instructions::reduce_instructions;
use super::remove_meta_lines::remove_meta_lines;
@@ -12,7 +11,6 @@ use super::simplify::simplify;
use super::simplify_jumps::simplify_jumps;
pub fn optimize(module: &mut Module, pointer_allocator: &mut NameAllocator) {
collapse_pointers_of_pointers(module);
shake_tree(module);
let passes = 3;

View File

@@ -2017,7 +2017,7 @@ impl ScopeAnalysis {
for (_span, ref_) in self.refs.range(start..end) {
let name = self.names.get(&ref_.name_id).unwrap();
if let Value::Register(_) = &name.value {
if let Value::Undefined | Value::Register(_) = &name.value {
continue;
}

View File

@@ -1,7 +1,9 @@
use swc_common::BytePos;
use tiny_keccak::{Hasher, Keccak};
pub fn src_hash(source: &str, span: swc_common::Span) -> [u8; 32] {
use crate::asm::Hash;
pub fn src_hash(source: &str, span: swc_common::Span) -> Hash {
let BytePos(start) = span.lo;
let BytePos(end) = span.hi;
@@ -16,5 +18,5 @@ pub fn src_hash(source: &str, span: swc_common::Span) -> [u8; 32] {
let mut output = [0u8; 32];
k.finalize(&mut output);
output
Hash(output)
}

View File

@@ -60,7 +60,7 @@ where
self.value(Some(&definition.pointer), dep);
}
}
ContentHashable::Hash(_) => {}
ContentHashable::Content(_) => {}
},
DefinitionContent::Value(value) => {
self.value(Some(&definition.pointer), value);