jazz_vm/
function.rs

1use std::any::Any;
2use std::cell::RefCell;
3use object::Object;
4use object_pool::ObjectPool;
5use basic_block::BasicBlock;
6use executor::ExecutorImpl;
7use errors;
8use function_optimizer::FunctionOptimizer;
9use value::Value;
10
11pub enum Function {
12    Virtual(RefCell<VirtualFunction>),
13    Native(NativeFunction)
14}
15
16pub struct VirtualFunction {
17    basic_blocks: Vec<BasicBlock>,
18    rt_handles: Vec<usize>,
19    should_optimize: bool,
20    this: Option<Value>
21}
22
23#[derive(Serialize, Deserialize, Clone, Debug)]
24pub struct VirtualFunctionInfo {
25    pub basic_blocks: Vec<BasicBlock>
26}
27
28pub type NativeFunction = Box<Fn(&mut ExecutorImpl) -> Value + Send>;
29
30impl Object for Function {
31    fn initialize(&mut self, pool: &mut ObjectPool) {
32        self.static_optimize(pool);
33    }
34
35    fn get_children(&self) -> Vec<usize> {
36        match *self {
37            Function::Virtual(ref f) => f.borrow().rt_handles.clone(),
38            Function::Native(_) => Vec::new()
39        }
40    }
41
42    fn as_any(&self) -> &Any {
43        self as &Any
44    }
45
46    fn as_any_mut(&mut self) -> &mut Any {
47        self as &mut Any
48    }
49
50    fn call(&self, executor: &mut ExecutorImpl) -> Value {
51        match *self {
52            Function::Virtual(ref vf) => {
53                let vf = vf.borrow();
54                if let Some(this) = vf.this {
55                    executor.get_current_frame().set_this(this);
56                }
57                executor.eval_basic_blocks(vf.basic_blocks.as_slice(), 0)
58            },
59            Function::Native(ref nf) => {
60                nf(executor)
61            }
62        }
63    }
64}
65
66impl Function {
67    pub fn from_basic_blocks(blocks: Vec<BasicBlock>) -> Function {
68        let vf = VirtualFunction {
69            basic_blocks: blocks,
70            rt_handles: Vec::new(),
71            should_optimize: false,
72            this: None
73        };
74        println!("{:?}",vf.basic_blocks);
75        vf.validate().unwrap_or_else(|e| {
76            panic!(errors::VMError::from(e))
77        });
78
79        Function::Virtual(RefCell::new(vf))
80    }
81
82    pub fn bind_this(&self, this: Value) {
83        if let Function::Virtual(ref f) = *self {
84            if let Ok(mut f) = f.try_borrow_mut() {
85                if f.this.is_some() {
86                    panic!(errors::VMError::from("Cannot rebind this"));
87                }
88                f.this = Some(this);
89                if let Value::Object(id) = this {
90                    f.rt_handles.push(id);
91                }
92            } else {
93                panic!(errors::VMError::from("Cannot bind from inside the function"));
94            }
95        } else {
96            panic!(errors::VMError::from("Binding this is only supported on virtual functions"));
97        }
98    }
99
100    pub fn enable_optimization(&mut self) {
101        if let Function::Virtual(ref mut f) = *self {
102            f.borrow_mut().should_optimize = true;
103        }
104    }
105
106    pub fn from_native(nf: NativeFunction) -> Function {
107        Function::Native(nf)
108    }
109
110    pub fn to_virtual_info(&self) -> Option<VirtualFunctionInfo> {
111        match *self {
112            Function::Virtual(ref vf) => Some(VirtualFunctionInfo {
113                basic_blocks: vf.borrow().basic_blocks.clone()
114            }),
115            Function::Native(_) => None
116        }
117    }
118
119    pub fn from_virtual_info(vinfo: VirtualFunctionInfo) -> Self {
120        Function::from_basic_blocks(vinfo.basic_blocks)
121    }
122
123    pub fn static_optimize(&self, pool: &mut ObjectPool) {
124        if let Function::Virtual(ref f) = *self {
125            if let Ok(mut f) = f.try_borrow_mut() {
126                if f.should_optimize {
127                    f.static_optimize(pool);
128                }
129            } else {
130                panic!(errors::VMError::from("Cannot optimize virtual functions within itself"));
131            }
132        }
133    }
134
135    pub fn dynamic_optimize(&self, pool: &mut ObjectPool) {
136        if let Function::Virtual(ref f) = *self {
137            if let Ok(mut f) = f.try_borrow_mut() {
138                if f.should_optimize {
139                    f.dynamic_optimize(pool);
140                }
141            } else {
142                panic!(errors::VMError::from("Cannot optimize virtual functions within itself"));
143            }
144        }
145    }
146}
147
148impl VirtualFunction {
149    fn static_optimize(&mut self, pool: &mut ObjectPool) {
150        let mut optimizer = FunctionOptimizer::new(&mut self.basic_blocks, &mut self.rt_handles, pool);
151        optimizer.set_binded_this(self.this);
152        optimizer.static_optimize();
153    }
154
155    fn dynamic_optimize(&mut self, pool: &mut ObjectPool) {
156        let mut optimizer = FunctionOptimizer::new(&mut self.basic_blocks, &mut self.rt_handles, pool);
157        optimizer.set_binded_this(self.this);
158        optimizer.dynamic_optimize();
159    }
160
161    pub fn validate(&self) -> Result<(), errors::ValidateError> {
162        self.validate_basic_blocks()?;
163        self.validate_branch_targets()?;
164        Ok(())
165    }
166
167    pub fn validate_basic_blocks(&self) -> Result<(), errors::ValidateError> {
168        for bb in &self.basic_blocks {
169            bb.validate(false)?;
170        }
171
172        Ok(())
173    }
174
175    pub fn validate_branch_targets(&self) -> Result<(), errors::ValidateError> {
176        let blocks = &self.basic_blocks;
177
178        for bb in blocks {
179            let mut found_error: bool = false;
180
181            let (fst, snd) = bb.branch_targets();
182            if let Some(fst) = fst {
183                if fst >= blocks.len() {
184                    found_error = true;
185                }
186            }
187            if let Some(snd) = snd {
188                if snd >= blocks.len() {
189                    found_error = true;
190                }
191            }
192
193            if found_error {
194                return Err(errors::ValidateError::new("Invalid branch target(s)"));
195            }
196        }
197
198        Ok(())
199    }
200}