Sfoglia il codice sorgente

Remove LOAD, as they are preexecuted

Cesar Rodas 9 mesi fa
parent
commit
32c1b594f2

+ 1 - 0
utxo/src/filter_expr/compiler/mod.rs

@@ -157,6 +157,7 @@ impl<'a> Compiler<'a> {
             optimizations::remove_unused_values,
             optimizations::calculate_static_values,
             optimizations::remove_useless_jumps,
+            optimizations::move_load_top,
         ]
         .into_iter()
         .fold((opcodes, false), |(opcodes, has_optimized), f| {

+ 2 - 1
utxo/src/filter_expr/compiler/optimizations/mod.rs

@@ -1,10 +1,11 @@
 mod assign_unique_register_address;
 mod calculate_static_values;
+mod move_load_top;
 mod remove_redundant_load_and_mov;
 mod remove_unused_values;
 mod remove_useless_jumps;
 
 pub use self::{
-    assign_unique_register_address::*, calculate_static_values::*,
+    assign_unique_register_address::*, calculate_static_values::*, move_load_top::*,
     remove_redundant_load_and_mov::*, remove_unused_values::*, remove_useless_jumps::*,
 };

+ 0 - 1
utxo/src/filter_expr/compiler/optimizations/remove_redundant_load_and_mov.rs

@@ -5,7 +5,6 @@ pub fn remove_redundant_load_and_mov(mut opcodes: Vec<OpCode>) -> (Vec<OpCode>,
     let new_opcodes = opcodes.into_iter().fold(Vec::new(), |mut acc, current| {
         if let OpCode::MOV(target, from) = &current {
             if let Some(last) = acc.last_mut() {
-                println!("herex: {:?} {:?}", last, current);
                 match last {
                     OpCode::LOAD(reg, _) => {
                         if reg == from {

+ 50 - 35
utxo/src/filter_expr/filter.rs

@@ -11,25 +11,23 @@ use crate::Transaction;
 use std::collections::HashMap;
 
 #[derive(Debug, Clone)]
-pub struct Filter {
+pub struct Filter<'a> {
     /// Query
     query: Query,
     /// List of external variables
     variables: Vec<Variable>,
+    /// Unoptimized opcodes
+    dbg_opcodes: Vec<OpCode>,
     /// Opcodes with human readable labels
     opcodes: Vec<OpCode>,
     /// The list of opcodes that make up the program, the labels has been converted into addresses
     opcodes_to_execute: Vec<OpCode>,
-    /// If the program has some boilerplate that can be skipped. This is non-zero when the initial
-    /// program has been executed at compile time, and the register has been populated to
-    /// `initial_register`. Everytime a new Runtime is created, instead of executing the program,
-    /// it can safely start-off a different Address, and clone the initial_register.
-    start_at: Addr,
     /// The state of the register
-    initial_register: Vec<Value>,
+    initial_register: HashMap<Register, ValueOrRef<'a>>,
+    _phantom: std::marker::PhantomData<&'a ()>,
 }
 
-impl Filter {
+impl<'a> Filter<'a> {
     pub fn new(code: &str) -> Result<Self, Error> {
         let query = parse_query(code)?;
         let opcodes = query.where_clause.as_ref().map_or_else(
@@ -42,8 +40,9 @@ impl Filter {
             |expr| Compiler::new(expr).compile(),
         )?;
 
-        Ok(Self {
+        let instance = Self {
             query,
+            dbg_opcodes: opcodes.clone(),
             opcodes: opcodes.clone(),
             variables: opcodes
                 .iter()
@@ -53,19 +52,40 @@ impl Filter {
                 })
                 .collect(),
             opcodes_to_execute: Compiler::resolve_label_to_addr(opcodes)?,
-            start_at: 0.into(),
-            initial_register: vec![],
-        })
+            initial_register: HashMap::new(),
+            _phantom: std::marker::PhantomData,
+        };
+        Ok(instance.optimize())
     }
 
-    /// Attempts to optiomize the `raw_opcodes` inside the Filter. Returns a tuple with the new
-    /// self with the optimized opcodes, and a boolean indicating if the program was optimized.
-    pub fn optimize_round(mut self) -> (Self, bool) {
-        let (new_opcodes, has_changed) = Compiler::optimize(self.opcodes);
-        self.opcodes = new_opcodes;
-        self.opcodes_to_execute = Compiler::resolve_label_to_addr(self.opcodes.clone()).unwrap();
+    /// Optimizes the program
+    pub fn optimize(mut self) -> Self {
+        let mut new_opcodes = self.opcodes;
+        loop {
+            let (new_opcodes_, has_changed) = Compiler::optimize(new_opcodes);
+            new_opcodes = new_opcodes_;
+            if !has_changed {
+                break;
+            }
+        }
 
-        (self, has_changed)
+        self.opcodes = new_opcodes;
+        self.initial_register.clear();
+        self.opcodes_to_execute = Compiler::resolve_label_to_addr(
+            self.opcodes
+                .iter()
+                .filter_map(|opcode| match opcode {
+                    OpCode::LOAD(addr, value) => {
+                        self.initial_register
+                            .insert(*addr, ValueOrRef::Value(value.clone()));
+                        None
+                    }
+                    _ => Some(opcode.clone()),
+                })
+                .collect(),
+        )
+        .unwrap();
+        self
     }
 
     /// Returns a human readable version of the compiled program (generated op-codes)
@@ -89,7 +109,7 @@ impl Filter {
             .join("\n")
     }
 
-    pub fn execute<'a>(
+    pub fn execute(
         &'a self,
         external_variables: &'a HashMap<Variable, ValueOrRef<'a>>,
     ) -> Result<Value, Error> {
@@ -97,7 +117,6 @@ impl Filter {
             external_variables,
             &self.opcodes_to_execute,
             self.initial_register.clone(),
-            self.start_at,
         )
     }
 }
@@ -122,14 +141,8 @@ mod test {
         .unwrap();
         println!("{}\n", x.dump());
 
-        loop {
-            let (new_x, is_done) = x.optimize_round();
-            println!("{}\n", new_x.dump());
-            x = new_x;
-            if !is_done {
-                break;
-            }
-        }
+        let mut x = x.optimize();
+        println!("{}\n", x.dump());
 
         let external_variables_1 = vec![
             ("foo".into(), ValueOrRef::Value(0.into())),
@@ -155,13 +168,15 @@ mod test {
         .into_iter()
         .collect();
 
-        let value = x.execute(&external_variables_1).expect("valid execution");
-        assert!(matches!(value, Value::Bool(false)));
+        for i in 0..100_000 {
+            let value = x.execute(&external_variables_1).expect("valid execution");
+            assert!(matches!(value, Value::Bool(false)));
 
-        let value = x.execute(&external_variables_2).expect("valid execution");
-        assert!(matches!(value, Value::Bool(false)));
+            let value = x.execute(&external_variables_2).expect("valid execution");
+            assert!(matches!(value, Value::Bool(false)));
 
-        let value = x.execute(&external_variables_3).expect("valid execution");
-        assert!(matches!(value, Value::Bool(true)));
+            let value = x.execute(&external_variables_3).expect("valid execution");
+            assert!(matches!(value, Value::Bool(true)));
+        }
     }
 }

+ 3 - 8
utxo/src/filter_expr/runtime.rs

@@ -39,15 +39,10 @@ macro_rules! set {
 pub fn execute<'a>(
     external_variables: &'a HashMap<Variable, ValueOrRef<'a>>,
     code: &'a [OpCode],
-    initial_registers: Vec<Value>,
-    start_at: Addr,
+    initial_registers: HashMap<Register, ValueOrRef<'a>>,
 ) -> Result<Value, Error> {
-    let mut execution = start_at;
-    let mut registers = initial_registers
-        .iter()
-        .enumerate()
-        .map(|(pos, a)| (pos.into(), a.into()))
-        .collect::<HashMap<Register, ValueOrRef>>();
+    let mut execution: Addr = 0.into();
+    let mut registers = initial_registers;
 
     loop {
         match code.get(*execution).ok_or(Error::OutOfBoundaries)? {