mirror of
https://github.com/fluencelabs/wasm-utils
synced 2025-07-31 05:52:03 +00:00
indirect_call bug fix
This commit is contained in:
@@ -209,6 +209,9 @@ pub fn optimize(
|
||||
if eliminated_globals.len() > 0 {
|
||||
update_global_index(func_body.code_mut().elements_mut(), &eliminated_globals)
|
||||
}
|
||||
if eliminated_types.len() > 0 {
|
||||
update_type_index(func_body.code_mut(), &eliminated_types)
|
||||
}
|
||||
}
|
||||
},
|
||||
&mut elements::Section::Export(ref mut export_section) => {
|
||||
@@ -290,6 +293,24 @@ pub fn update_global_index(opcodes: &mut Vec<elements::Opcode>, eliminated_indic
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates global references considering the _ordered_ list of eliminated indices
|
||||
pub fn update_type_index(opcodes: &mut elements::Opcodes, eliminated_indices: &[usize]) {
|
||||
use parity_wasm::elements::Opcode::*;
|
||||
for opcode in opcodes.elements_mut().iter_mut() {
|
||||
match opcode {
|
||||
&mut Block(_, ref mut block) | &mut If(_, ref mut block) | &mut Loop(_, ref mut block) => {
|
||||
update_call_index(block, eliminated_indices)
|
||||
},
|
||||
&mut CallIndirect(ref mut call_index, _) => {
|
||||
let totalle = eliminated_indices.iter().take_while(|i| (**i as u32) < *call_index).count();
|
||||
trace!("rewired call_indrect {} -> call_indirect {}", *call_index, *call_index - totalle as u32);
|
||||
*call_index -= totalle as u32;
|
||||
},
|
||||
_ => { },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn import_section<'a>(module: &'a mut elements::Module) -> Option<&'a mut elements::ImportSection> {
|
||||
for section in module.sections_mut() {
|
||||
match section {
|
||||
@@ -547,4 +568,53 @@ mod tests {
|
||||
"There should 2 (two) functions in the optimized module"
|
||||
);
|
||||
}
|
||||
|
||||
/// @spec 4
|
||||
/// Imagine the unoptimized module has an indirect call to function of type 1
|
||||
/// The type should persist so that indirect call would work
|
||||
#[test]
|
||||
fn call_indirect() {
|
||||
let mut module = builder::module()
|
||||
.function()
|
||||
.signature().param().i32().param().i32().build()
|
||||
.build()
|
||||
.function()
|
||||
.signature().param().i32().param().i32().build()
|
||||
.build()
|
||||
.function()
|
||||
.signature().param().i32().build()
|
||||
.body()
|
||||
.with_opcodes(elements::Opcodes::new(
|
||||
vec![
|
||||
elements::Opcode::CallIndirect(1, false),
|
||||
elements::Opcode::End
|
||||
]
|
||||
))
|
||||
.build()
|
||||
.build()
|
||||
.export()
|
||||
.field("_call")
|
||||
.internal().func(2).build()
|
||||
.build();
|
||||
|
||||
optimize(&mut module, vec!["_call"]).expect("optimizer to succeed");
|
||||
|
||||
assert_eq!(
|
||||
2,
|
||||
module.type_section().expect("type section to be generated").types().len(),
|
||||
"There should 2 (two) types left in the module, 1 for indirect call and one for _call"
|
||||
);
|
||||
|
||||
let indirect_opcode = &module.code_section().expect("code section to be generated").bodies()[0].code().elements()[0];
|
||||
match *indirect_opcode {
|
||||
elements::Opcode::CallIndirect(0, false) => {},
|
||||
_ => {
|
||||
panic!(
|
||||
"Expected call_indirect to use index 0 after optimization, since previois 0th was eliminated, but got {:?}",
|
||||
indirect_opcode
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -56,6 +56,9 @@ pub fn push_code_symbols(module: &elements::Module, opcodes: &[elements::Opcode]
|
||||
&Call(idx) => {
|
||||
dest.push(resolve_function(module, idx));
|
||||
},
|
||||
&CallIndirect(idx, _) => {
|
||||
dest.push(Symbol::Type(idx as usize));
|
||||
},
|
||||
&GetGlobal(idx) | &SetGlobal(idx) => {
|
||||
dest.push(resolve_global(module, idx))
|
||||
},
|
||||
|
Reference in New Issue
Block a user