mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-01-13 23:48:02 -05:00
Split out optimization dir
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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<Module>,
|
||||
|
||||
@@ -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::<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();
|
||||
}
|
||||
});
|
||||
}
|
||||
126
valuescript_compiler/src/optimization/extract_constants.rs
Normal file
126
valuescript_compiler/src/optimization/extract_constants.rs
Normal file
@@ -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::<Value, Pointer>::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<String> {
|
||||
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
|
||||
}
|
||||
6
valuescript_compiler/src/optimization/mod.rs
Normal file
6
valuescript_compiler/src/optimization/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
mod collapse_pointers_of_pointers;
|
||||
mod extract_constants;
|
||||
mod optimize;
|
||||
mod shake_tree;
|
||||
|
||||
pub use optimize::optimize;
|
||||
12
valuescript_compiler/src/optimization/optimize.rs
Normal file
12
valuescript_compiler/src/optimization/optimize.rs
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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::<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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn shake_tree(module: &mut Module) {
|
||||
pub fn shake_tree(module: &mut Module) {
|
||||
let mut dependency_graph = HashMap::<Pointer, HashSet<Pointer>>::new();
|
||||
let mut reverse_dependency_graph = HashMap::<Pointer, HashSet<Pointer>>::new();
|
||||
let mut pointers_to_include = Vec::<Pointer>::new();
|
||||
@@ -195,121 +157,3 @@ fn gather_required_pointers(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_constants(module: &mut Module, pointer_allocator: &mut NameAllocator) {
|
||||
let mut constants = HashMap::<Value, Pointer>::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<String> {
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user