diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 5046953..bf03275 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -171,6 +171,18 @@ impl<'a> WasmFuncBackend<'a> { } func.instruction(&wasm_encoder::Instruction::Return); } + WasmBlock::ReturnCall { func: f,values } => { + for &value in &values[..] { + self.lower_value(value, func); + } + func.instruction(&wasm_encoder::Instruction::ReturnCall(f.index() as u32)); + } + WasmBlock::ReturnCallIndirect { sig, table, values } => { + for &value in &values[..] { + self.lower_value(value, func); + } + func.instruction(&wasm_encoder::Instruction::ReturnCallIndirect { ty: sig.index() as u32, table: table.index() as u32 }); + } WasmBlock::Unreachable => { func.instruction(&wasm_encoder::Instruction::Unreachable); } diff --git a/src/backend/stackify.rs b/src/backend/stackify.rs index 2c6d48e..f26b583 100644 --- a/src/backend/stackify.rs +++ b/src/backend/stackify.rs @@ -9,6 +9,7 @@ //! //! for more details on how this algorithm works. +use crate::{Func, Signature, Table}; use crate::cfg::CFGInfo; use crate::entity::EntityRef; use crate::ir::{Block, BlockTarget, FunctionBody, Terminator, Type, Value}; @@ -52,6 +53,8 @@ pub enum WasmBlock<'a> { }, /// A function return instruction. Return { values: &'a [Value] }, + ReturnCall { func: Func,values: &'a [Value] }, + ReturnCallIndirect { sig: Signature,table: Table,values: &'a [Value] }, /// An unreachable instruction. Unreachable, } @@ -441,6 +444,12 @@ impl<'a, 'b> Context<'a, 'b> { &Terminator::Unreachable | &Terminator::None => { into.push(WasmBlock::Unreachable); } + &Terminator::ReturnCall { func, ref args } => { + into.push(WasmBlock::ReturnCall { func: func, values: args }); + } + &Terminator::ReturnCallIndirect { sig, table, ref args } => { + into.push(WasmBlock::ReturnCallIndirect { sig, table, values: args }) + } } } } diff --git a/src/frontend.rs b/src/frontend.rs index 0c21fab..d9a3a13 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -1230,6 +1230,18 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { self.emit_ret(&retvals[..]); self.reachable = false; } + wasmparser::Operator::ReturnCall { function_index } => { + let sig = self.module.funcs[Func::new(*function_index as usize)].sig(); + let retvals = self.pop_n(self.module.signatures[sig].params.len()); + self.emit_term(Terminator::ReturnCall { func: Func::new(*function_index as usize), args: retvals }); + self.reachable = false; + } + wasmparser::Operator::ReturnCallIndirect { type_index, table_index } => { + // let sig = self.module.funcs[Func::new(*function_index as usize)].sig(); + let retvals = self.pop_n(self.module.signatures[Signature::new(*type_index as usize)].params.len()); + self.emit_term(Terminator::ReturnCallIndirect { sig: Signature::new(*type_index as usize), table: Table::new(*table_index as usize),args: retvals }); + self.reachable = false; + } _ => bail!(FrontendError::UnsupportedFeature(format!( "Unsupported operator: {:?}", @@ -1647,6 +1659,21 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { } } + fn emit_term(&mut self, t: Terminator){ + log::trace!( + "emit_term: cur_block {} reachable {} terminator {:?}", + self.cur_block, + self.reachable, + t + ); + if self.reachable { + // let values = values.to_vec(); + self.body + .set_terminator(self.cur_block,t); + self.reachable = false; + } + } + fn emit_unreachable(&mut self) { log::trace!( "emit_unreachable: cur_block {} reachable {}", diff --git a/src/interp.rs b/src/interp.rs index b6657e1..c08bebb 100644 --- a/src/interp.rs +++ b/src/interp.rs @@ -227,6 +227,34 @@ impl InterpContext { } match &body.blocks[frame.cur_block].terminator { + &Terminator::ReturnCallIndirect { sig, table, ref args } => { + let args = args + .iter() + .map(|&arg| { + let arg = body.resolve_alias(arg); + let multivalue = frame.values.get(&arg).unwrap(); + assert_eq!(multivalue.len(), 1); + multivalue[0] + }) + .collect::>(); + let idx = args.last().unwrap().as_u32().unwrap() as usize; + let func = self.tables[table].elements[idx]; + let result = self.call(module, func, &args[..args.len() - 1]); + return result; + } + &Terminator::ReturnCall { func, ref args } => { + let args = args + .iter() + .map(|&arg| { + let arg = body.resolve_alias(arg); + let multivalue = frame.values.get(&arg).unwrap(); + assert_eq!(multivalue.len(), 1); + multivalue[0] + }) + .collect::>(); + let result = self.call(module, func, &args[..]); + return result; + } &Terminator::None => { return InterpResult::Trap(frame.func, frame.cur_block, u32::MAX) } diff --git a/src/ir/func.rs b/src/ir/func.rs index 32117e0..4d06cae 100644 --- a/src/ir/func.rs +++ b/src/ir/func.rs @@ -1,4 +1,5 @@ use super::{Block, FunctionBodyDisplay, Local, Module, Signature, Type, Value, ValueDef}; +use crate::{Func, Table}; use crate::backend::WasmFuncBackend; use crate::cfg::CFGInfo; use crate::entity::{EntityRef, EntityVec, PerEntity}; @@ -536,6 +537,15 @@ pub enum Terminator { Return { values: Vec, }, + ReturnCall { + func: Func, + args: Vec, + }, + ReturnCallIndirect { + sig: Signature, + table: Table, + args: Vec, + }, Unreachable, None, } @@ -581,6 +591,26 @@ impl std::fmt::Display for Terminator { .join(", ") )?, Terminator::Unreachable => write!(f, "unreachable")?, + Terminator::ReturnCall { func, args } => write!( + f, + "return_call {}({})", + func, + args + .iter() + .map(|val| format!("{}", val)) + .collect::>() + .join(", ") + )?, + Terminator::ReturnCallIndirect { sig, table, args } => write!( + f, + "return_call_indirect ({};{})({})", + sig,table, + args + .iter() + .map(|val| format!("{}", val)) + .collect::>() + .join(", ") + )?, } Ok(()) } @@ -611,6 +641,8 @@ impl Terminator { } Terminator::None => {} Terminator::Unreachable => {} + Terminator::ReturnCall { func, args } =>{}, + Terminator::ReturnCallIndirect { sig, table, args } => {}, } } @@ -638,6 +670,8 @@ impl Terminator { } Terminator::None => {} Terminator::Unreachable => {} + Terminator::ReturnCall { func, args } =>{}, + Terminator::ReturnCallIndirect { sig, table, args } => {}, } } @@ -717,6 +751,16 @@ impl Terminator { f(value); } } + &Terminator::ReturnCall { func, ref args } => { + for value in args{ + f(*value); + } + } + &Terminator::ReturnCallIndirect { sig, table, ref args } => { + for value in args{ + f(*value); + } + }, _ => {} } } @@ -735,6 +779,16 @@ impl Terminator { f(value); } } + &mut Terminator::ReturnCall { func, ref mut args } => { + for value in args{ + f(value); + } + } + &mut Terminator::ReturnCallIndirect { sig, table, ref mut args } => { + for value in args{ + f(value); + } + }, _ => {} } } diff --git a/src/passes.rs b/src/passes.rs index c6d4a58..be8a888 100644 --- a/src/passes.rs +++ b/src/passes.rs @@ -8,3 +8,4 @@ pub mod remove_phis; pub mod resolve_aliases; pub mod ssa; pub mod trace; +pub mod reorder_funs; \ No newline at end of file diff --git a/src/passes/reorder_funs.rs b/src/passes/reorder_funs.rs new file mode 100644 index 0000000..139413a --- /dev/null +++ b/src/passes/reorder_funs.rs @@ -0,0 +1,69 @@ +use std::collections::BTreeMap; + +use crate::{ExportKind, Func, FuncDecl, FunctionBody, ImportKind, Module, Operator, ValueDef, entity::EntityRef, Terminator}; + +pub fn reorder_funcs_in_body(b: &mut FunctionBody, f: &BTreeMap) { + for v in b.values.values_mut() { + if let ValueDef::Operator(a, _, _) = v { + if let Operator::Call { function_index } = a { + *function_index = *f.get(&*function_index).unwrap(); + } + } + } + for k in b.blocks.values_mut(){ + if let Terminator::ReturnCall { func, args } = &mut k.terminator{ + *func = *f.get(&*func).unwrap(); + } + } +} +pub fn reorder_funcs(m: &mut Module, fs: &BTreeMap) { + let mut n = m.funcs.clone(); + for (f, b) in m.funcs.entries() { + let mut b = b.clone(); + if let Some(b) = b.body_mut() { + reorder_funcs_in_body(b, fs); + } + n[*fs.get(&f).unwrap()] = b; + } + m.funcs = n; + for t in m.tables.values_mut() { + if let Some(e) = t.func_elements.as_mut() { + for e in e.iter_mut() { + *e = *fs.get(&*e).unwrap(); + } + } + } + for i in m.imports.iter_mut() { + if let ImportKind::Func(f) = &mut i.kind { + *f = *fs.get(&*f).unwrap(); + } + } + for i in m.exports.iter_mut() { + if let ExportKind::Func(f) = &mut i.kind { + *f = *fs.get(&*f).unwrap(); + } + } +} +pub fn fixup_orders(m: &mut Module) { + let mut fs = BTreeMap::new(); + let mut a = vec![]; + let mut b = vec![]; + for (f, d) in m.funcs.entries() { + if let FuncDecl::Import(_, _) = d { + a.push(f) + } else { + b.push(f) + } + } + let mut i = 0; + for v in a{ + fs.insert(v, Func::new(i)); + i += 1; + } + for v in b{ + fs.insert(v, Func::new(i)); + i += 1; + } + reorder_funcs(m, &fs); + return; +}