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), Native(NativeFunction) } pub struct VirtualFunction { basic_blocks: Vec, rt_handles: Vec, should_optimize: bool, this: Option } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct VirtualFunctionInfo { pub basic_blocks: Vec } pub type NativeFunction = Box Value + Send>; impl Object for Function { fn initialize(&mut self, pool: &mut ObjectPool) { self.static_optimize(pool); } fn get_children(&self) -> Vec { 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) -> 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 { 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(()) } }