hexagon 0.1.2

The Hexagon VM
Documentation
use std::any::Any;
use std::cell::RefCell;
use object::Object;
use object_pool::ObjectPool;
use basic_block::BasicBlock;
use executor::ExecutorImpl;
use errors;
use function_optimizer::FunctionOptimizer;
use value::Value;

pub enum Function {
    Virtual(RefCell<VirtualFunction>),
    Native(NativeFunction)
}

pub struct VirtualFunction {
    basic_blocks: Vec<BasicBlock>,
    rt_handles: Vec<usize>,
    should_optimize: bool,
    this: Option<Value>
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct VirtualFunctionInfo {
    pub basic_blocks: Vec<BasicBlock>
}

pub type NativeFunction = Box<Fn(&mut ExecutorImpl) -> Value + Send>;

impl Object for Function {
    fn initialize(&mut self, pool: &mut ObjectPool) {
        self.static_optimize(pool);
    }

    fn get_children(&self) -> Vec<usize> {
        match *self {
            Function::Virtual(ref f) => f.borrow().rt_handles.clone(),
            Function::Native(_) => Vec::new()
        }
    }

    fn as_any(&self) -> &Any {
        self as &Any
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self as &mut Any
    }

    fn call(&self, executor: &mut ExecutorImpl) -> Value {
        match *self {
            Function::Virtual(ref vf) => {
                let vf = vf.borrow();
                if let Some(this) = vf.this {
                    executor.get_current_frame().set_this(this);
                }
                executor.eval_basic_blocks(vf.basic_blocks.as_slice(), 0)
            },
            Function::Native(ref nf) => {
                nf(executor)
            }
        }
    }
}

impl Function {
    pub fn from_basic_blocks(blocks: Vec<BasicBlock>) -> Function {
        let vf = VirtualFunction {
            basic_blocks: blocks,
            rt_handles: Vec::new(),
            should_optimize: false,
            this: None
        };

        vf.validate().unwrap_or_else(|e| {
            panic!(errors::VMError::from(e))
        });

        Function::Virtual(RefCell::new(vf))
    }

    pub fn bind_this(&self, this: Value) {
        if let Function::Virtual(ref f) = *self {
            if let Ok(mut f) = f.try_borrow_mut() {
                if f.this.is_some() {
                    panic!(errors::VMError::from("Cannot rebind this"));
                }
                f.this = Some(this);
                if let Value::Object(id) = this {
                    f.rt_handles.push(id);
                }
            } else {
                panic!(errors::VMError::from("Cannot bind from inside the function"));
            }
        } else {
            panic!(errors::VMError::from("Binding this is only supported on virtual functions"));
        }
    }

    pub fn enable_optimization(&mut self) {
        if let Function::Virtual(ref mut f) = *self {
            f.borrow_mut().should_optimize = true;
        }
    }

    pub fn from_native(nf: NativeFunction) -> Function {
        Function::Native(nf)
    }

    pub fn to_virtual_info(&self) -> Option<VirtualFunctionInfo> {
        match *self {
            Function::Virtual(ref vf) => Some(VirtualFunctionInfo {
                basic_blocks: vf.borrow().basic_blocks.clone()
            }),
            Function::Native(_) => None
        }
    }

    pub fn from_virtual_info(vinfo: VirtualFunctionInfo) -> Self {
        Function::from_basic_blocks(vinfo.basic_blocks)
    }

    pub fn static_optimize(&self, pool: &mut ObjectPool) {
        if let Function::Virtual(ref f) = *self {
            if let Ok(mut f) = f.try_borrow_mut() {
                if f.should_optimize {
                    f.static_optimize(pool);
                }
            } else {
                panic!(errors::VMError::from("Cannot optimize virtual functions within itself"));
            }
        }
    }

    pub fn dynamic_optimize(&self, pool: &mut ObjectPool) {
        if let Function::Virtual(ref f) = *self {
            if let Ok(mut f) = f.try_borrow_mut() {
                if f.should_optimize {
                    f.dynamic_optimize(pool);
                }
            } else {
                panic!(errors::VMError::from("Cannot optimize virtual functions within itself"));
            }
        }
    }
}

impl VirtualFunction {
    fn static_optimize(&mut self, pool: &mut ObjectPool) {
        let mut optimizer = FunctionOptimizer::new(&mut self.basic_blocks, &mut self.rt_handles, pool);
        optimizer.set_binded_this(self.this);
        optimizer.static_optimize();
    }

    fn dynamic_optimize(&mut self, pool: &mut ObjectPool) {
        let mut optimizer = FunctionOptimizer::new(&mut self.basic_blocks, &mut self.rt_handles, pool);
        optimizer.set_binded_this(self.this);
        optimizer.dynamic_optimize();
    }

    pub fn validate(&self) -> Result<(), errors::ValidateError> {
        self.validate_basic_blocks()?;
        self.validate_branch_targets()?;
        Ok(())
    }

    pub fn validate_basic_blocks(&self) -> Result<(), errors::ValidateError> {
        for bb in &self.basic_blocks {
            bb.validate(false)?;
        }

        Ok(())
    }

    pub fn validate_branch_targets(&self) -> Result<(), errors::ValidateError> {
        let blocks = &self.basic_blocks;

        for bb in blocks {
            let mut found_error: bool = false;

            let (fst, snd) = bb.branch_targets();
            if let Some(fst) = fst {
                if fst >= blocks.len() {
                    found_error = true;
                }
            }
            if let Some(snd) = snd {
                if snd >= blocks.len() {
                    found_error = true;
                }
            }

            if found_error {
                return Err(errors::ValidateError::new("Invalid branch target(s)"));
            }
        }

        Ok(())
    }
}