mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
Extract optimize.rs
This commit is contained in:
@@ -12,11 +12,13 @@ mod instruction_mutates_this;
|
||||
mod link_module;
|
||||
mod module_compiler;
|
||||
mod name_allocator;
|
||||
mod optimize;
|
||||
mod resolve_path;
|
||||
mod scope;
|
||||
mod scope_analysis;
|
||||
mod static_eval_expr;
|
||||
mod target_accessor;
|
||||
mod visit_pointers;
|
||||
|
||||
pub use assembler::assemble;
|
||||
pub use assembly_parser::parse_module;
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::mem::take;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::asm::{
|
||||
Array, Definition, DefinitionContent, FnLine, Instruction, InstructionFieldMut, Object, Pointer,
|
||||
Value,
|
||||
};
|
||||
use crate::asm::{Definition, DefinitionContent, FnLine, Instruction, Object, Pointer, Value};
|
||||
use crate::gather_modules::PathAndModule;
|
||||
use crate::import_pattern::{ImportKind, ImportPattern};
|
||||
use crate::name_allocator::NameAllocator;
|
||||
use crate::resolve_path::{resolve_path, ResolvedPath};
|
||||
use crate::DiagnosticLevel;
|
||||
use crate::visit_pointers::{visit_pointers, PointerVisitation};
|
||||
use crate::{asm::Module, Diagnostic};
|
||||
use crate::{optimize::optimize, DiagnosticLevel};
|
||||
|
||||
pub struct LinkModuleResult {
|
||||
pub module: Option<Module>,
|
||||
@@ -108,9 +105,7 @@ pub fn link_module(
|
||||
&mut result.diagnostics,
|
||||
);
|
||||
|
||||
collapse_pointers_of_pointers(&mut path_and_module.module);
|
||||
shake_tree(&mut path_and_module.module);
|
||||
extract_constants(&mut path_and_module.module, &mut pointer_allocator);
|
||||
optimize(&mut path_and_module.module, &mut pointer_allocator);
|
||||
|
||||
result.module = Some(path_and_module.module);
|
||||
result
|
||||
@@ -140,180 +135,6 @@ fn rewrite_pointers(module: &mut Module, pointer_allocator: &mut NameAllocator)
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_pointers<Visitor>(module: &mut Module, visitor: Visitor)
|
||||
where
|
||||
Visitor: FnMut(PointerVisitation) -> (),
|
||||
{
|
||||
let mut pointer_visitor = VisitPointerImpl::new(visitor);
|
||||
pointer_visitor.module(module);
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
enum PointerVisitation<'a> {
|
||||
Export(&'a mut Pointer),
|
||||
Definition(&'a mut Pointer),
|
||||
Reference(&'a Pointer, &'a mut Pointer),
|
||||
}
|
||||
|
||||
struct VisitPointerImpl<Visitor>
|
||||
where
|
||||
Visitor: FnMut(PointerVisitation) -> (),
|
||||
{
|
||||
visitor: Visitor,
|
||||
}
|
||||
|
||||
impl<Visitor> VisitPointerImpl<Visitor>
|
||||
where
|
||||
Visitor: FnMut(PointerVisitation) -> (),
|
||||
{
|
||||
fn new(visitor: Visitor) -> Self {
|
||||
Self { visitor }
|
||||
}
|
||||
|
||||
pub fn module(&mut self, module: &mut Module) {
|
||||
self.value(None, &mut module.export_default);
|
||||
self.object(None, &mut module.export_star);
|
||||
|
||||
for definition in &mut module.definitions {
|
||||
self.definition(definition);
|
||||
}
|
||||
}
|
||||
|
||||
fn definition(&mut self, definition: &mut Definition) {
|
||||
(self.visitor)(PointerVisitation::Definition(&mut definition.pointer));
|
||||
|
||||
match &mut definition.content {
|
||||
DefinitionContent::Function(function) => {
|
||||
self.body(&definition.pointer, &mut function.body);
|
||||
}
|
||||
DefinitionContent::Class(class) => {
|
||||
self.value(Some(&definition.pointer), &mut class.constructor);
|
||||
self.value(Some(&definition.pointer), &mut class.prototype);
|
||||
self.value(Some(&definition.pointer), &mut class.static_);
|
||||
}
|
||||
DefinitionContent::Value(value) => {
|
||||
self.value(Some(&definition.pointer), value);
|
||||
}
|
||||
DefinitionContent::Lazy(lazy) => {
|
||||
self.body(&definition.pointer, &mut lazy.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array(&mut self, owner: Option<&Pointer>, array: &mut Array) {
|
||||
for value in &mut array.values {
|
||||
self.value(owner, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn object(&mut self, owner: Option<&Pointer>, object: &mut Object) {
|
||||
for (key, value) in object.properties.iter_mut() {
|
||||
self.value(owner, key);
|
||||
self.value(owner, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self, owner: Option<&Pointer>, value: &mut Value) {
|
||||
use Value::*;
|
||||
|
||||
match value {
|
||||
Void | Undefined | Null | Bool(_) | Number(_) | BigInt(_) | String(_) | Register(_)
|
||||
| Builtin(_) => {}
|
||||
Array(array) => {
|
||||
self.array(owner, array);
|
||||
}
|
||||
Object(object) => {
|
||||
self.object(owner, object);
|
||||
}
|
||||
Pointer(pointer) => {
|
||||
(self.visitor)(match owner {
|
||||
Some(owner) => PointerVisitation::Reference(owner, pointer),
|
||||
None => PointerVisitation::Export(pointer),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn instruction(&mut self, owner: &Pointer, instruction: &mut Instruction) {
|
||||
use Instruction::*;
|
||||
|
||||
match instruction {
|
||||
End | UnsetCatch | RequireMutableThis | OpInc(..) | OpDec(..) | Jmp(..) | SetCatch(..)
|
||||
| Next(..) | UnpackIterRes(..) => {}
|
||||
Mov(arg, _)
|
||||
| OpNot(arg, _)
|
||||
| OpBitNot(arg, _)
|
||||
| TypeOf(arg, _)
|
||||
| UnaryPlus(arg, _)
|
||||
| UnaryMinus(arg, _)
|
||||
| Import(arg, _)
|
||||
| ImportStar(arg, _)
|
||||
| Throw(arg)
|
||||
| Cat(arg, _)
|
||||
| Yield(arg, _)
|
||||
| YieldStar(arg, _) => {
|
||||
self.value(Some(owner), arg);
|
||||
}
|
||||
OpPlus(arg1, arg2, _)
|
||||
| OpMinus(arg1, arg2, _)
|
||||
| OpMul(arg1, arg2, _)
|
||||
| OpDiv(arg1, arg2, _)
|
||||
| OpMod(arg1, arg2, _)
|
||||
| OpExp(arg1, arg2, _)
|
||||
| OpEq(arg1, arg2, _)
|
||||
| OpNe(arg1, arg2, _)
|
||||
| OpTripleEq(arg1, arg2, _)
|
||||
| OpTripleNe(arg1, arg2, _)
|
||||
| OpAnd(arg1, arg2, _)
|
||||
| OpOr(arg1, arg2, _)
|
||||
| OpLess(arg1, arg2, _)
|
||||
| OpLessEq(arg1, arg2, _)
|
||||
| OpGreater(arg1, arg2, _)
|
||||
| OpGreaterEq(arg1, arg2, _)
|
||||
| OpNullishCoalesce(arg1, arg2, _)
|
||||
| OpOptionalChain(arg1, arg2, _)
|
||||
| OpBitAnd(arg1, arg2, _)
|
||||
| OpBitOr(arg1, arg2, _)
|
||||
| OpBitXor(arg1, arg2, _)
|
||||
| OpLeftShift(arg1, arg2, _)
|
||||
| OpRightShift(arg1, arg2, _)
|
||||
| OpRightShiftUnsigned(arg1, arg2, _)
|
||||
| InstanceOf(arg1, arg2, _)
|
||||
| In(arg1, arg2, _)
|
||||
| Call(arg1, arg2, _)
|
||||
| Bind(arg1, arg2, _)
|
||||
| Sub(arg1, arg2, _)
|
||||
| SubMov(arg1, arg2, _)
|
||||
| New(arg1, arg2, _) => {
|
||||
self.value(Some(owner), arg1);
|
||||
self.value(Some(owner), arg2);
|
||||
}
|
||||
Apply(arg1, arg2, arg3, _)
|
||||
| SubCall(arg1, arg2, arg3, _)
|
||||
| ConstSubCall(arg1, arg2, arg3, _)
|
||||
| ThisSubCall(arg1, arg2, arg3, _) => {
|
||||
self.value(Some(owner), arg1);
|
||||
self.value(Some(owner), arg2);
|
||||
self.value(Some(owner), arg3);
|
||||
}
|
||||
JmpIf(arg, _) => {
|
||||
self.value(Some(owner), arg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn body(&mut self, owner: &Pointer, body: &mut Vec<FnLine>) {
|
||||
for fn_line in body {
|
||||
match fn_line {
|
||||
FnLine::Instruction(instruction) => {
|
||||
self.instruction(owner, instruction);
|
||||
}
|
||||
FnLine::Label(..) | FnLine::Empty | FnLine::Comment(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_and_rewrite_import_patterns(path_and_module: &mut PathAndModule) -> Vec<ResolvedPath> {
|
||||
let mut resolved_paths = Vec::<ResolvedPath>::new();
|
||||
|
||||
@@ -394,171 +215,3 @@ fn link_import_patterns(
|
||||
*definition = new_definition;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
let mut dependency_graph = HashMap::<Pointer, HashSet<Pointer>>::new();
|
||||
let mut pointers_to_include = Vec::<Pointer>::new();
|
||||
|
||||
visit_pointers(module, |visitation| match visitation {
|
||||
PointerVisitation::Export(exported_pointer) => {
|
||||
pointers_to_include.push(exported_pointer.clone());
|
||||
}
|
||||
PointerVisitation::Definition(_) => {}
|
||||
PointerVisitation::Reference(owner, pointer) => {
|
||||
dependency_graph
|
||||
.entry(owner.clone())
|
||||
.or_default()
|
||||
.insert(pointer.clone());
|
||||
}
|
||||
});
|
||||
|
||||
let mut pointers_included = HashSet::<Pointer>::new();
|
||||
let mut pointers_to_include_i = 0;
|
||||
|
||||
while pointers_to_include_i < pointers_to_include.len() {
|
||||
let pointer = &pointers_to_include[pointers_to_include_i];
|
||||
pointers_to_include_i += 1;
|
||||
|
||||
pointers_included.insert(pointer.clone());
|
||||
|
||||
if let Some(dependencies) = dependency_graph.get(pointer) {
|
||||
// TODO: Avoid randomness caused by HashSet iteration
|
||||
for dependency in dependencies {
|
||||
if !pointers_included.contains(dependency) {
|
||||
pointers_to_include.push(dependency.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let previous_definitions = std::mem::take(&mut module.definitions);
|
||||
let mut new_definitions_map = HashMap::<Pointer, Definition>::new();
|
||||
|
||||
for definition in previous_definitions {
|
||||
if pointers_included.contains(&definition.pointer) {
|
||||
new_definitions_map.insert(definition.pointer.clone(), definition);
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_definitions = Vec::<Definition>::new();
|
||||
|
||||
for pointer in &pointers_to_include {
|
||||
let defn = new_definitions_map.get_mut(pointer).unwrap();
|
||||
|
||||
if let DefinitionContent::Value(_) = defn.content {
|
||||
// Exclude values on the first pass. TODO: Proper depth-first search (+reverse) to ensure
|
||||
// correct ordering.
|
||||
continue;
|
||||
}
|
||||
|
||||
if defn.pointer.name != "" {
|
||||
new_definitions.push(take(defn));
|
||||
}
|
||||
}
|
||||
|
||||
for pointer in pointers_to_include {
|
||||
let defn = new_definitions_map.get_mut(&pointer).unwrap();
|
||||
|
||||
if defn.pointer.name != "" {
|
||||
new_definitions.push(take(defn));
|
||||
}
|
||||
}
|
||||
|
||||
module.definitions = new_definitions;
|
||||
}
|
||||
|
||||
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 let Value::String(s) = value {
|
||||
if s.len() >= 4 {
|
||||
return Some(mangle_string(s));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
181
valuescript_compiler/src/optimize.rs
Normal file
181
valuescript_compiler/src/optimize.rs
Normal file
@@ -0,0 +1,181 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::mem::take;
|
||||
|
||||
use crate::asm::Module;
|
||||
use crate::asm::{Definition, DefinitionContent, FnLine, InstructionFieldMut, Pointer, Value};
|
||||
use crate::name_allocator::NameAllocator;
|
||||
use crate::visit_pointers::{visit_pointers, PointerVisitation};
|
||||
|
||||
pub fn optimize(module: &mut Module, pointer_allocator: &mut NameAllocator) {
|
||||
collapse_pointers_of_pointers(module);
|
||||
shake_tree(module);
|
||||
extract_constants(module, pointer_allocator);
|
||||
}
|
||||
|
||||
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) {
|
||||
let mut dependency_graph = HashMap::<Pointer, HashSet<Pointer>>::new();
|
||||
let mut pointers_to_include = Vec::<Pointer>::new();
|
||||
|
||||
visit_pointers(module, |visitation| match visitation {
|
||||
PointerVisitation::Export(exported_pointer) => {
|
||||
pointers_to_include.push(exported_pointer.clone());
|
||||
}
|
||||
PointerVisitation::Definition(_) => {}
|
||||
PointerVisitation::Reference(owner, pointer) => {
|
||||
dependency_graph
|
||||
.entry(owner.clone())
|
||||
.or_default()
|
||||
.insert(pointer.clone());
|
||||
}
|
||||
});
|
||||
|
||||
let mut pointers_included = HashSet::<Pointer>::new();
|
||||
let mut pointers_to_include_i = 0;
|
||||
|
||||
while pointers_to_include_i < pointers_to_include.len() {
|
||||
let pointer = &pointers_to_include[pointers_to_include_i];
|
||||
pointers_to_include_i += 1;
|
||||
|
||||
pointers_included.insert(pointer.clone());
|
||||
|
||||
if let Some(dependencies) = dependency_graph.get(pointer) {
|
||||
// TODO: Avoid randomness caused by HashSet iteration
|
||||
for dependency in dependencies {
|
||||
if !pointers_included.contains(dependency) {
|
||||
pointers_to_include.push(dependency.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let previous_definitions = std::mem::take(&mut module.definitions);
|
||||
let mut new_definitions_map = HashMap::<Pointer, Definition>::new();
|
||||
|
||||
for definition in previous_definitions {
|
||||
if pointers_included.contains(&definition.pointer) {
|
||||
new_definitions_map.insert(definition.pointer.clone(), definition);
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_definitions = Vec::<Definition>::new();
|
||||
|
||||
for pointer in &pointers_to_include {
|
||||
let defn = new_definitions_map.get_mut(pointer).unwrap();
|
||||
|
||||
if let DefinitionContent::Value(_) = defn.content {
|
||||
// Exclude values on the first pass. TODO: Proper depth-first search (+reverse) to ensure
|
||||
// correct ordering.
|
||||
continue;
|
||||
}
|
||||
|
||||
if defn.pointer.name != "" {
|
||||
new_definitions.push(take(defn));
|
||||
}
|
||||
}
|
||||
|
||||
for pointer in pointers_to_include {
|
||||
let defn = new_definitions_map.get_mut(&pointer).unwrap();
|
||||
|
||||
if defn.pointer.name != "" {
|
||||
new_definitions.push(take(defn));
|
||||
}
|
||||
}
|
||||
|
||||
module.definitions = new_definitions;
|
||||
}
|
||||
|
||||
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 let Value::String(s) = value {
|
||||
if s.len() >= 4 {
|
||||
return Some(mangle_string(s));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
177
valuescript_compiler/src/visit_pointers.rs
Normal file
177
valuescript_compiler/src/visit_pointers.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
use crate::asm::{
|
||||
Array, Definition, DefinitionContent, FnLine, Instruction, Module, Object, Pointer, Value,
|
||||
};
|
||||
|
||||
pub fn visit_pointers<Visitor>(module: &mut Module, visitor: Visitor)
|
||||
where
|
||||
Visitor: FnMut(PointerVisitation) -> (),
|
||||
{
|
||||
let mut pointer_visitor = VisitPointerImpl::new(visitor);
|
||||
pointer_visitor.module(module);
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum PointerVisitation<'a> {
|
||||
Export(&'a mut Pointer),
|
||||
Definition(&'a mut Pointer),
|
||||
Reference(&'a Pointer, &'a mut Pointer),
|
||||
}
|
||||
|
||||
struct VisitPointerImpl<Visitor>
|
||||
where
|
||||
Visitor: FnMut(PointerVisitation) -> (),
|
||||
{
|
||||
visitor: Visitor,
|
||||
}
|
||||
|
||||
impl<Visitor> VisitPointerImpl<Visitor>
|
||||
where
|
||||
Visitor: FnMut(PointerVisitation) -> (),
|
||||
{
|
||||
fn new(visitor: Visitor) -> Self {
|
||||
Self { visitor }
|
||||
}
|
||||
|
||||
pub fn module(&mut self, module: &mut Module) {
|
||||
self.value(None, &mut module.export_default);
|
||||
self.object(None, &mut module.export_star);
|
||||
|
||||
for definition in &mut module.definitions {
|
||||
self.definition(definition);
|
||||
}
|
||||
}
|
||||
|
||||
fn definition(&mut self, definition: &mut Definition) {
|
||||
(self.visitor)(PointerVisitation::Definition(&mut definition.pointer));
|
||||
|
||||
match &mut definition.content {
|
||||
DefinitionContent::Function(function) => {
|
||||
self.body(&definition.pointer, &mut function.body);
|
||||
}
|
||||
DefinitionContent::Class(class) => {
|
||||
self.value(Some(&definition.pointer), &mut class.constructor);
|
||||
self.value(Some(&definition.pointer), &mut class.prototype);
|
||||
self.value(Some(&definition.pointer), &mut class.static_);
|
||||
}
|
||||
DefinitionContent::Value(value) => {
|
||||
self.value(Some(&definition.pointer), value);
|
||||
}
|
||||
DefinitionContent::Lazy(lazy) => {
|
||||
self.body(&definition.pointer, &mut lazy.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array(&mut self, owner: Option<&Pointer>, array: &mut Array) {
|
||||
for value in &mut array.values {
|
||||
self.value(owner, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn object(&mut self, owner: Option<&Pointer>, object: &mut Object) {
|
||||
for (key, value) in object.properties.iter_mut() {
|
||||
self.value(owner, key);
|
||||
self.value(owner, value);
|
||||
}
|
||||
}
|
||||
|
||||
fn value(&mut self, owner: Option<&Pointer>, value: &mut Value) {
|
||||
use Value::*;
|
||||
|
||||
match value {
|
||||
Void | Undefined | Null | Bool(_) | Number(_) | BigInt(_) | String(_) | Register(_)
|
||||
| Builtin(_) => {}
|
||||
Array(array) => {
|
||||
self.array(owner, array);
|
||||
}
|
||||
Object(object) => {
|
||||
self.object(owner, object);
|
||||
}
|
||||
Pointer(pointer) => {
|
||||
(self.visitor)(match owner {
|
||||
Some(owner) => PointerVisitation::Reference(owner, pointer),
|
||||
None => PointerVisitation::Export(pointer),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn instruction(&mut self, owner: &Pointer, instruction: &mut Instruction) {
|
||||
use Instruction::*;
|
||||
|
||||
match instruction {
|
||||
End | UnsetCatch | RequireMutableThis | OpInc(..) | OpDec(..) | Jmp(..) | SetCatch(..)
|
||||
| Next(..) | UnpackIterRes(..) => {}
|
||||
Mov(arg, _)
|
||||
| OpNot(arg, _)
|
||||
| OpBitNot(arg, _)
|
||||
| TypeOf(arg, _)
|
||||
| UnaryPlus(arg, _)
|
||||
| UnaryMinus(arg, _)
|
||||
| Import(arg, _)
|
||||
| ImportStar(arg, _)
|
||||
| Throw(arg)
|
||||
| Cat(arg, _)
|
||||
| Yield(arg, _)
|
||||
| YieldStar(arg, _) => {
|
||||
self.value(Some(owner), arg);
|
||||
}
|
||||
OpPlus(arg1, arg2, _)
|
||||
| OpMinus(arg1, arg2, _)
|
||||
| OpMul(arg1, arg2, _)
|
||||
| OpDiv(arg1, arg2, _)
|
||||
| OpMod(arg1, arg2, _)
|
||||
| OpExp(arg1, arg2, _)
|
||||
| OpEq(arg1, arg2, _)
|
||||
| OpNe(arg1, arg2, _)
|
||||
| OpTripleEq(arg1, arg2, _)
|
||||
| OpTripleNe(arg1, arg2, _)
|
||||
| OpAnd(arg1, arg2, _)
|
||||
| OpOr(arg1, arg2, _)
|
||||
| OpLess(arg1, arg2, _)
|
||||
| OpLessEq(arg1, arg2, _)
|
||||
| OpGreater(arg1, arg2, _)
|
||||
| OpGreaterEq(arg1, arg2, _)
|
||||
| OpNullishCoalesce(arg1, arg2, _)
|
||||
| OpOptionalChain(arg1, arg2, _)
|
||||
| OpBitAnd(arg1, arg2, _)
|
||||
| OpBitOr(arg1, arg2, _)
|
||||
| OpBitXor(arg1, arg2, _)
|
||||
| OpLeftShift(arg1, arg2, _)
|
||||
| OpRightShift(arg1, arg2, _)
|
||||
| OpRightShiftUnsigned(arg1, arg2, _)
|
||||
| InstanceOf(arg1, arg2, _)
|
||||
| In(arg1, arg2, _)
|
||||
| Call(arg1, arg2, _)
|
||||
| Bind(arg1, arg2, _)
|
||||
| Sub(arg1, arg2, _)
|
||||
| SubMov(arg1, arg2, _)
|
||||
| New(arg1, arg2, _) => {
|
||||
self.value(Some(owner), arg1);
|
||||
self.value(Some(owner), arg2);
|
||||
}
|
||||
Apply(arg1, arg2, arg3, _)
|
||||
| SubCall(arg1, arg2, arg3, _)
|
||||
| ConstSubCall(arg1, arg2, arg3, _)
|
||||
| ThisSubCall(arg1, arg2, arg3, _) => {
|
||||
self.value(Some(owner), arg1);
|
||||
self.value(Some(owner), arg2);
|
||||
self.value(Some(owner), arg3);
|
||||
}
|
||||
JmpIf(arg, _) => {
|
||||
self.value(Some(owner), arg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn body(&mut self, owner: &Pointer, body: &mut Vec<FnLine>) {
|
||||
for fn_line in body {
|
||||
match fn_line {
|
||||
FnLine::Instruction(instruction) => {
|
||||
self.instruction(owner, instruction);
|
||||
}
|
||||
FnLine::Label(..) | FnLine::Empty | FnLine::Comment(..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user