diff --git a/src/graph.rs b/src/graph.rs index 1fa3099..5cc65ea 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -895,7 +895,7 @@ mod tests { _ => panic!("instruction #2 should be a call!"), } }, - _ => panic!("func #4 should be declared!"), + _ => panic!("func #3 should be declared!"), }, Some(2), "Call should be recalculated to 2" @@ -904,4 +904,69 @@ mod tests { validate_sample(&sample); } + + #[test] + fn simple_opt() { + let mut sample = load_sample(r#" +(module + (type (;0;) (func)) + (type (;1;) (func (param i32 i32) (result i32))) + (type (;2;) (func (param i32 i32) (result i32))) + (type (;3;) (func (param i32 i32) (result i32))) + (import "env" "foo" (func (type 1))) + (import "env" "foo2" (func (type 2))) + (import "env" "foo3" (func (type 3))) + (func (type 0) + i32.const 1 + i32.const 1 + call 0 + drop + ) + (func (type 0) + i32.const 2 + i32.const 2 + call 1 + drop + ) + (func (type 0) + i32.const 3 + i32.const 3 + call 2 + drop + ) + (func (type 0) + call 3 + ) + +)"# + ); + + validate_sample(&sample); + + // we'll delete functions #4 and #5, nobody references it so it should be fine; + + sample.funcs.begin_delete().push(4).push(5).done(); + validate_sample(&sample); + + // now we'll delete functions #1 and #2 (imported and called from the deleted above), + // should also be fine + sample.funcs.begin_delete().push(1).push(2).done(); + validate_sample(&sample); + + // now the last declared function left should call another one before it (which is index #1) + let declared_func_2 = sample.funcs.clone_ref(2); + assert_eq!( + match &declared_func_2.read().origin { + super::ImportedOrDeclared::Declared(ref body) => { + match body.code[0] { + super::Instruction::Call(ref called_func) => called_func.order(), + ref wrong_instruction => panic!("instruction #2 should be a call but got {:?}!", wrong_instruction), + } + }, + _ => panic!("func #0 should be declared!"), + }, + Some(1), + "Call should be recalculated to 1" + ); + } } \ No newline at end of file diff --git a/src/ref_list.rs b/src/ref_list.rs index 2d0d3f2..8c35ed2 100644 --- a/src/ref_list.rs +++ b/src/ref_list.rs @@ -192,11 +192,6 @@ impl RefList { } fn done_delete(&mut self, indices: &[usize]) { - for idx in indices { - let mut detached = self.items.remove(*idx); - detached.write().index = EntryOrigin::Detached; - } - for index in 0..self.items.len() { let mut next_entry = self.items.get_mut(index).expect("Checked above; qed").write(); let total_less = indices.iter() @@ -207,6 +202,14 @@ impl RefList { EntryOrigin::Index(ref mut idx) => { *idx -= total_less; }, }; } + + let mut total_removed = 0; + for idx in indices { + let mut detached = self.items.remove(*idx - total_removed); + detached.write().index = EntryOrigin::Detached; + total_removed += 1; + } + } fn done_insert(&mut self, index: usize, mut items: Vec>) { @@ -356,6 +359,34 @@ mod tests { assert_eq!(item20.order(), None); } + #[test] + fn complex_delete() { + let mut list = RefList::::new(); + let item00 = list.push(0); + let item10 = list.push(10); + let item20 = list.push(20); + let item30 = list.push(30); + let item40 = list.push(40); + let item50 = list.push(50); + let item60 = list.push(60); + let item70 = list.push(70); + let item80 = list.push(80); + let item90 = list.push(90); + + list.begin_delete().push(1).push(2).push(4).push(6).done(); + + assert_eq!(item00.order(), Some(0)); + assert_eq!(item10.order(), None); + assert_eq!(item20.order(), None); + assert_eq!(item30.order(), Some(1)); + assert_eq!(item40.order(), None); + assert_eq!(item50.order(), Some(2)); + assert_eq!(item60.order(), None); + assert_eq!(item70.order(), Some(3)); + assert_eq!(item80.order(), Some(4)); + assert_eq!(item90.order(), Some(5)); + } + #[test] fn insert() { let mut list = RefList::::new();