diff --git a/valuescript_compiler/src/lib.rs b/valuescript_compiler/src/lib.rs index 934e6e7..7306ab5 100644 --- a/valuescript_compiler/src/lib.rs +++ b/valuescript_compiler/src/lib.rs @@ -12,7 +12,7 @@ mod instruction_mutates_this; mod link_module; mod module_compiler; mod name_allocator; -mod optimize; +mod optimization; mod resolve_path; mod scope; mod scope_analysis; diff --git a/valuescript_compiler/src/link_module.rs b/valuescript_compiler/src/link_module.rs index aedc5ea..5df97e3 100644 --- a/valuescript_compiler/src/link_module.rs +++ b/valuescript_compiler/src/link_module.rs @@ -4,10 +4,11 @@ use crate::asm::{Definition, DefinitionContent, FnLine, Instruction, Object, Poi use crate::gather_modules::PathAndModule; use crate::import_pattern::{ImportKind, ImportPattern}; use crate::name_allocator::NameAllocator; +use crate::optimization::optimize; use crate::resolve_path::{resolve_path, ResolvedPath}; use crate::visit_pointers::{visit_pointers, PointerVisitation}; +use crate::DiagnosticLevel; use crate::{asm::Module, Diagnostic}; -use crate::{optimize::optimize, DiagnosticLevel}; pub struct LinkModuleResult { pub module: Option, diff --git a/valuescript_compiler/src/optimization/collapse_pointers_of_pointers.rs b/valuescript_compiler/src/optimization/collapse_pointers_of_pointers.rs new file mode 100644 index 0000000..fca5606 --- /dev/null +++ b/valuescript_compiler/src/optimization/collapse_pointers_of_pointers.rs @@ -0,0 +1,37 @@ +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::::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(); + } + }); +} diff --git a/valuescript_compiler/src/optimization/extract_constants.rs b/valuescript_compiler/src/optimization/extract_constants.rs new file mode 100644 index 0000000..f29de35 --- /dev/null +++ b/valuescript_compiler/src/optimization/extract_constants.rs @@ -0,0 +1,126 @@ +use std::{collections::HashMap, mem::take}; + +use crate::{ + asm::{ + Definition, DefinitionContent, FnLine, InstructionFieldMut, Module, Number, Pointer, Value, + }, + name_allocator::NameAllocator, +}; + +pub fn extract_constants(module: &mut Module, pointer_allocator: &mut NameAllocator) { + let mut constants = HashMap::::new(); + + for defn in &mut module.definitions { + if let DefinitionContent::Function(f) = &mut defn.content { + for line in &mut f.body { + if let FnLine::Instruction(instr) = line { + instr.visit_fields_mut(&mut |field| match field { + InstructionFieldMut::Value(value) => { + value.visit_values_mut(&mut |sub_value| { + if let Some(p) = constants.get(&sub_value) { + *sub_value = Value::Pointer(p.clone()); + return; + } + + if let Some(name) = should_extract_value_as_constant(&sub_value) { + let p = Pointer { + name: pointer_allocator.allocate(&name), + }; + + let existing_p = constants.insert(take(sub_value), p.clone()); + assert!(existing_p.is_none()); + *sub_value = Value::Pointer(p); + } + }); + } + InstructionFieldMut::Register(_) | InstructionFieldMut::LabelRef(_) => {} + }); + } + } + } + } + + for (value, pointer) in constants { + module.definitions.push(Definition { + pointer, + content: DefinitionContent::Value(value), + }); + } +} + +fn should_extract_value_as_constant(value: &Value) -> Option { + if !is_constant(value) { + return None; + } + + match value { + Value::Void + | Value::Undefined + | Value::Null + | Value::Bool(..) + | Value::Number(Number(..)) + | Value::BigInt(..) + | Value::Pointer(..) + | Value::Builtin(..) + | Value::Register(..) => None, + Value::String(s) => { + if s.len() >= 4 { + Some(mangle_string(s)) + } else { + None + } + } + Value::Array(array) => { + if array.values.iter().all(is_constant) { + Some("array".to_string()) + } else { + None + } + } + Value::Object(object) => { + if object + .properties + .iter() + .all(|(k, v)| is_constant(k) && is_constant(v)) + { + Some("object".to_string()) + } else { + None + } + } + } +} + +fn is_constant(value: &Value) -> bool { + match value { + Value::Void + | Value::Undefined + | Value::Null + | Value::Bool(..) + | Value::Number(Number(..)) + | Value::BigInt(..) + | Value::String(..) + | Value::Pointer(..) + | Value::Builtin(..) => true, + Value::Register(..) => false, + Value::Array(array) => array.values.iter().all(is_constant), + Value::Object(object) => object + .properties + .iter() + .all(|(k, v)| is_constant(k) && is_constant(v)), + } +} + +fn mangle_string(s: &String) -> String { + let mut res = "s_".to_string(); + + for c in s.chars() { + if c.is_ascii_alphanumeric() { + res.push(c); + } else { + res.push('_'); + } + } + + res +} diff --git a/valuescript_compiler/src/optimization/mod.rs b/valuescript_compiler/src/optimization/mod.rs new file mode 100644 index 0000000..d6329dc --- /dev/null +++ b/valuescript_compiler/src/optimization/mod.rs @@ -0,0 +1,6 @@ +mod collapse_pointers_of_pointers; +mod extract_constants; +mod optimize; +mod shake_tree; + +pub use optimize::optimize; diff --git a/valuescript_compiler/src/optimization/optimize.rs b/valuescript_compiler/src/optimization/optimize.rs new file mode 100644 index 0000000..a87942c --- /dev/null +++ b/valuescript_compiler/src/optimization/optimize.rs @@ -0,0 +1,12 @@ +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::shake_tree::shake_tree; + +pub fn optimize(module: &mut Module, pointer_allocator: &mut NameAllocator) { + collapse_pointers_of_pointers(module); + extract_constants(module, pointer_allocator); + shake_tree(module); +} diff --git a/valuescript_compiler/src/optimize.rs b/valuescript_compiler/src/optimization/shake_tree.rs similarity index 50% rename from valuescript_compiler/src/optimize.rs rename to valuescript_compiler/src/optimization/shake_tree.rs index 21b0083..7c3d145 100644 --- a/valuescript_compiler/src/optimize.rs +++ b/valuescript_compiler/src/optimization/shake_tree.rs @@ -1,49 +1,11 @@ use std::collections::{HashMap, HashSet}; use std::mem::take; -use crate::asm::{Definition, DefinitionContent, FnLine, InstructionFieldMut, Pointer, Value}; -use crate::asm::{Module, Number}; -use crate::name_allocator::NameAllocator; +use crate::asm::Module; +use crate::asm::{Definition, DefinitionContent, Pointer}; use crate::visit_pointers::{visit_pointers, PointerVisitation}; -pub fn optimize(module: &mut Module, pointer_allocator: &mut NameAllocator) { - collapse_pointers_of_pointers(module); - extract_constants(module, pointer_allocator); - shake_tree(module); -} - -fn collapse_pointers_of_pointers(module: &mut Module) { - let mut double_pointer_map = HashMap::::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(); - } - }); -} - -fn shake_tree(module: &mut Module) { +pub fn shake_tree(module: &mut Module) { let mut dependency_graph = HashMap::>::new(); let mut reverse_dependency_graph = HashMap::>::new(); let mut pointers_to_include = Vec::::new(); @@ -195,121 +157,3 @@ fn gather_required_pointers( } } } - -fn extract_constants(module: &mut Module, pointer_allocator: &mut NameAllocator) { - let mut constants = HashMap::::new(); - - for defn in &mut module.definitions { - if let DefinitionContent::Function(f) = &mut defn.content { - for line in &mut f.body { - if let FnLine::Instruction(instr) = line { - instr.visit_fields_mut(&mut |field| match field { - InstructionFieldMut::Value(value) => { - value.visit_values_mut(&mut |sub_value| { - if let Some(p) = constants.get(&sub_value) { - *sub_value = Value::Pointer(p.clone()); - return; - } - - if let Some(name) = should_extract_value_as_constant(&sub_value) { - let p = Pointer { - name: pointer_allocator.allocate(&name), - }; - - let existing_p = constants.insert(take(sub_value), p.clone()); - assert!(existing_p.is_none()); - *sub_value = Value::Pointer(p); - } - }); - } - InstructionFieldMut::Register(_) | InstructionFieldMut::LabelRef(_) => {} - }); - } - } - } - } - - for (value, pointer) in constants { - module.definitions.push(Definition { - pointer, - content: DefinitionContent::Value(value), - }); - } -} - -fn should_extract_value_as_constant(value: &Value) -> Option { - if !is_constant(value) { - return None; - } - - match value { - Value::Void - | Value::Undefined - | Value::Null - | Value::Bool(..) - | Value::Number(Number(..)) - | Value::BigInt(..) - | Value::Pointer(..) - | Value::Builtin(..) - | Value::Register(..) => None, - Value::String(s) => { - if s.len() >= 4 { - Some(mangle_string(s)) - } else { - None - } - } - Value::Array(array) => { - if array.values.iter().all(is_constant) { - Some("array".to_string()) - } else { - None - } - } - Value::Object(object) => { - if object - .properties - .iter() - .all(|(k, v)| is_constant(k) && is_constant(v)) - { - Some("object".to_string()) - } else { - None - } - } - } -} - -fn is_constant(value: &Value) -> bool { - match value { - Value::Void - | Value::Undefined - | Value::Null - | Value::Bool(..) - | Value::Number(Number(..)) - | Value::BigInt(..) - | Value::String(..) - | Value::Pointer(..) - | Value::Builtin(..) => true, - Value::Register(..) => false, - Value::Array(array) => array.values.iter().all(is_constant), - Value::Object(object) => object - .properties - .iter() - .all(|(k, v)| is_constant(k) && is_constant(v)), - } -} - -fn mangle_string(s: &String) -> String { - let mut res = "s_".to_string(); - - for c in s.chars() { - if c.is_ascii_alphanumeric() { - res.push(c); - } else { - res.push('_'); - } - } - - res -}